Files
edx-platform/cms/static/js/views/modals/course_outline_modals.js
Zia Fazal 53cf5638b6 added radio input fields to pre-requisite selection
Initial changes to gate section based on completion percentage

code refactoring and added evaluation of completion milestone

Fixed broken unit tests and added new tests

Fixed broken tests and quality violations

Fixed Pep8 violation

Fixed eslint quality violations

Test changes as suggested by reviewer

changes after feedbacy from reviewer

Update the docstring with suggested changes

excluding chapter from the blocks

Disallow empty values for min score and min completion

Changes afte feedback from UX/Accessibility

removed blank line
2018-05-30 11:25:59 +05:00

1126 lines
40 KiB
JavaScript

/**
* The CourseOutlineXBlockModal is a Backbone view that shows an editor in a modal window.
* It has nested views: for release date, due date and grading format.
* It is invoked using the editXBlock method and uses xblock_info as a model,
* and upon save parent invokes refresh function that fetches updated model and
* re-renders edited course outline.
*/
define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
'js/views/modals/base_modal', 'date', 'js/views/utils/xblock_utils',
'js/utils/date_utils', 'edx-ui-toolkit/js/utils/html-utils',
'edx-ui-toolkit/js/utils/string-utils'
], function(
$, Backbone, _, gettext, BaseView, BaseModal, date, XBlockViewUtils, DateUtils, HtmlUtils, StringUtils
) {
'use strict';
var CourseOutlineXBlockModal, SettingsXBlockModal, PublishXBlockModal, HighlightsXBlockModal,
AbstractEditor, BaseDateEditor,
ReleaseDateEditor, DueDateEditor, GradingEditor, PublishEditor, AbstractVisibilityEditor,
StaffLockEditor, UnitAccessEditor, ContentVisibilityEditor, TimedExaminationPreferenceEditor,
AccessEditor, ShowCorrectnessEditor, HighlightsEditor, HighlightsEnableXBlockModal, HighlightsEnableEditor;
CourseOutlineXBlockModal = BaseModal.extend({
events: _.extend({}, BaseModal.prototype.events, {
'click .action-save': 'save',
keydown: 'keyHandler'
}),
options: $.extend({}, BaseModal.prototype.options, {
modalName: 'course-outline',
modalType: 'edit-settings',
addPrimaryActionButton: true,
modalSize: 'med',
viewSpecificClasses: 'confirm',
editors: []
}),
initialize: function() {
BaseModal.prototype.initialize.call(this);
this.template = this.loadTemplate('course-outline-modal');
this.options.title = this.getTitle();
},
afterRender: function() {
BaseModal.prototype.afterRender.call(this);
this.initializeEditors();
},
initializeEditors: function() {
this.options.editors = _.map(this.options.editors, function(Editor) {
return new Editor({
parentElement: this.$('.modal-section'),
model: this.model,
xblockType: this.options.xblockType,
enable_proctored_exams: this.options.enable_proctored_exams,
enable_timed_exams: this.options.enable_timed_exams
});
}, this);
},
getTitle: function() {
return '';
},
getIntroductionMessage: function() {
return '';
},
getContentHtml: function() {
return this.template(this.getContext());
},
save: function(event) {
event.preventDefault();
var requestData = this.getRequestData();
if (!_.isEqual(requestData, {metadata: {}})) {
XBlockViewUtils.updateXBlockFields(this.model, requestData, {
success: this.options.onSave
});
}
this.hide();
},
/**
* Return context for the modal.
* @return {Object}
*/
getContext: function() {
return $.extend({
xblockInfo: this.model,
introductionMessage: this.getIntroductionMessage(),
enable_proctored_exams: this.options.enable_proctored_exams,
enable_timed_exams: this.options.enable_timed_exams
});
},
/**
* Return request data.
* @return {Object}
*/
getRequestData: function() {
var requestData = _.map(this.options.editors, function(editor) {
return editor.getRequestData();
});
return $.extend.apply(this, [true, {}].concat(requestData));
},
keyHandler: function(event) {
if (event.which === 27) { // escape key
this.hide();
}
}
});
SettingsXBlockModal = CourseOutlineXBlockModal.extend({
getTitle: function() {
return StringUtils.interpolate(
gettext('{display_name} Settings'),
{display_name: this.model.get('display_name')}
);
},
initializeEditors: function() {
var tabs = this.options.tabs;
if (tabs && tabs.length > 0) {
if (tabs.length > 1) {
var tabsTemplate = this.loadTemplate('settings-modal-tabs');
HtmlUtils.setHtml(this.$('.modal-section'), HtmlUtils.HTML(tabsTemplate({tabs: tabs})));
_.each(this.options.tabs, function(tab) {
this.options.editors.push.apply(
this.options.editors,
_.map(tab.editors, function(Editor) {
return new Editor({
parent: this,
parentElement: this.$('.modal-section .' + tab.name),
model: this.model,
xblockType: this.options.xblockType,
enable_proctored_exams: this.options.enable_proctored_exams,
enable_timed_exams: this.options.enable_timed_exams
});
}, this)
);
}, this);
this.showTab(tabs[0].name);
} else {
this.options.editors = tabs[0].editors;
CourseOutlineXBlockModal.prototype.initializeEditors.call(this);
}
} else {
CourseOutlineXBlockModal.prototype.initializeEditors.call(this);
}
},
events: _.extend({}, CourseOutlineXBlockModal.prototype.events, {
'click .action-save': 'save',
'click .settings-tab-button': 'handleShowTab'
}),
/**
* Return request data.
* @return {Object}
*/
getRequestData: function() {
var requestData = _.map(this.options.editors, function(editor) {
return editor.getRequestData();
});
return $.extend.apply(this, [true, {}].concat(requestData));
},
handleShowTab: function(event) {
event.preventDefault();
this.showTab($(event.target).data('tab'));
},
showTab: function(tab) {
this.$('.modal-section .settings-tab-button').removeClass('active');
this.$('.modal-section .settings-tab-button[data-tab="' + tab + '"]').addClass('active');
this.$('.modal-section .settings-tab').hide();
this.$('.modal-section .' + tab).show();
}
});
PublishXBlockModal = CourseOutlineXBlockModal.extend({
events: _.extend({}, CourseOutlineXBlockModal.prototype.events, {
'click .action-publish': 'save'
}),
initialize: function() {
CourseOutlineXBlockModal.prototype.initialize.call(this);
if (this.options.xblockType) {
this.options.modalName = 'bulkpublish-' + this.options.xblockType;
}
},
getTitle: function() {
return StringUtils.interpolate(
gettext('Publish {display_name}'),
{display_name: this.model.get('display_name')}
);
},
getIntroductionMessage: function() {
return StringUtils.interpolate(
gettext('Publish all unpublished changes for this {item}?'),
{item: this.options.xblockType}
);
},
addActionButtons: function() {
this.addActionButton('publish', gettext('Publish'), true);
this.addActionButton('cancel', gettext('Cancel'));
}
});
HighlightsXBlockModal = CourseOutlineXBlockModal.extend({
events: _.extend({}, CourseOutlineXBlockModal.prototype.events, {
'click .action-save': 'callAnalytics',
'click .action-cancel': 'callAnalytics'
}),
initialize: function() {
CourseOutlineXBlockModal.prototype.initialize.call(this);
if (this.options.xblockType) {
this.options.modalName = 'highlights-' + this.options.xblockType;
}
},
getTitle: function() {
return StringUtils.interpolate(
gettext('Highlights for {display_name}'),
{display_name: this.model.get('display_name')}
);
},
getIntroductionMessage: function() {
return '';
},
callAnalytics: function(event) {
event.preventDefault();
window.analytics.track('edx.bi.highlights.' + event.target.innerText.toLowerCase());
if (event.target.className.indexOf('save') !== -1) {
this.save(event);
} else {
this.hide();
}
},
addActionButtons: function() {
this.addActionButton('save', gettext('Save'), true);
this.addActionButton('cancel', gettext('Cancel'));
}
});
HighlightsEnableXBlockModal = CourseOutlineXBlockModal.extend({
events: _.extend({}, CourseOutlineXBlockModal.prototype.events, {
'click .action-save': 'callAnalytics',
'click .action-cancel': 'callAnalytics'
}),
initialize: function() {
CourseOutlineXBlockModal.prototype.initialize.call(this);
if (this.options.xblockType) {
this.options.modalName = 'highlights-enable-' + this.options.xblockType;
}
},
getTitle: function() {
return gettext('Enable Weekly Highlight Emails');
},
getIntroductionMessage: function() {
return '';
},
callAnalytics: function(event) {
event.preventDefault();
window.analytics.track('edx.bi.highlights_enable.' + event.target.innerText.toLowerCase());
if (event.target.className.indexOf('save') !== -1) {
this.save(event);
} else {
this.hide();
}
},
addActionButtons: function() {
this.addActionButton('save', gettext('Enable'), true);
this.addActionButton('cancel', gettext('Not yet'));
}
});
AbstractEditor = BaseView.extend({
tagName: 'section',
templateName: null,
initialize: function() {
this.template = this.loadTemplate(this.templateName);
this.parent = this.options.parent;
this.parentElement = this.options.parentElement;
this.render();
},
render: function() {
var html = this.template($.extend({}, {
xblockInfo: this.model,
xblockType: this.options.xblockType,
enable_proctored_exam: this.options.enable_proctored_exams,
enable_timed_exam: this.options.enable_timed_exams
}, this.getContext()));
HtmlUtils.setHtml(this.$el, HtmlUtils.HTML(html));
this.parentElement.append(this.$el);
},
getContext: function() {
return {};
},
getRequestData: function() {
return {};
}
});
BaseDateEditor = AbstractEditor.extend({
// Attribute name in the model, should be defined in children classes.
fieldName: null,
events: {
'click .clear-date': 'clearValue'
},
afterRender: function() {
AbstractEditor.prototype.afterRender.call(this);
this.$('input.date').datepicker({dateFormat: 'm/d/yy'});
this.$('input.time').timepicker({
timeFormat: 'H:i',
forceRoundTime: false
});
if (this.model.get(this.fieldName)) {
DateUtils.setDate(
this.$('input.date'), this.$('input.time'),
this.model.get(this.fieldName)
);
}
}
});
DueDateEditor = BaseDateEditor.extend({
fieldName: 'due',
templateName: 'due-date-editor',
className: 'modal-section-content has-actions due-date-input grading-due-date',
getValue: function() {
return DateUtils.getDate(this.$('#due_date'), this.$('#due_time'));
},
clearValue: function(event) {
event.preventDefault();
this.$('#due_time, #due_date').val('');
},
getRequestData: function() {
return {
metadata: {
due: this.getValue()
}
};
}
});
ReleaseDateEditor = BaseDateEditor.extend({
fieldName: 'start',
templateName: 'release-date-editor',
className: 'edit-settings-release scheduled-date-input',
startingReleaseDate: null,
afterRender: function() {
BaseDateEditor.prototype.afterRender.call(this);
// Store the starting date and time so that we can determine if the user
// actually changed it when "Save" is pressed.
this.startingReleaseDate = this.getValue();
},
getValue: function() {
return DateUtils.getDate(this.$('#start_date'), this.$('#start_time'));
},
clearValue: function(event) {
event.preventDefault();
this.$('#start_time, #start_date').val('');
},
getRequestData: function() {
var newReleaseDate = this.getValue();
if (JSON.stringify(newReleaseDate) === JSON.stringify(this.startingReleaseDate)) {
return {};
}
return {
metadata: {
start: newReleaseDate
}
};
}
});
TimedExaminationPreferenceEditor = AbstractEditor.extend({
templateName: 'timed-examination-preference-editor',
className: 'edit-settings-timed-examination',
events: {
'change input.no_special_exam': 'notTimedExam',
'change input.timed_exam': 'setTimedExam',
'change input.practice_exam': 'setPracticeExam',
'change input.proctored_exam': 'setProctoredExam',
'focusout .field-time-limit input': 'timeLimitFocusout'
},
notTimedExam: function(event) {
event.preventDefault();
this.$('.exam-options').hide();
this.$('.field-time-limit input').val('00:00');
},
selectSpecialExam: function(showRulesField) {
this.$('.exam-options').show();
this.$('.field-time-limit').show();
if (!this.isValidTimeLimit(this.$('.field-time-limit input').val())) {
this.$('.field-time-limit input').val('00:30');
}
if (showRulesField) {
this.$('.field-exam-review-rules').show();
} else {
this.$('.field-exam-review-rules').hide();
}
},
setTimedExam: function(event) {
event.preventDefault();
this.selectSpecialExam(false);
},
setPracticeExam: function(event) {
event.preventDefault();
this.selectSpecialExam(false);
},
setProctoredExam: function(event) {
event.preventDefault();
this.selectSpecialExam(true);
},
timeLimitFocusout: function(event) {
event.preventDefault();
var selectedTimeLimit = $(event.currentTarget).val();
if (!this.isValidTimeLimit(selectedTimeLimit)) {
$(event.currentTarget).val('00:30');
}
},
afterRender: function() {
AbstractEditor.prototype.afterRender.call(this);
this.$('input.time').timepicker({
timeFormat: 'H:i',
minTime: '00:30',
maxTime: '24:00',
forceRoundTime: false
});
this.setExamType(this.model.get('is_time_limited'), this.model.get('is_proctored_exam'),
this.model.get('is_practice_exam'));
this.setExamTime(this.model.get('default_time_limit_minutes'));
this.setReviewRules(this.model.get('exam_review_rules'));
},
setExamType: function(is_time_limited, is_proctored_exam, is_practice_exam) {
this.$('.field-time-limit').hide();
this.$('.field-exam-review-rules').hide();
if (!is_time_limited) {
this.$('input.no_special_exam').prop('checked', true);
return;
}
this.$('.field-time-limit').show();
if (this.options.enable_proctored_exams && is_proctored_exam) {
if (is_practice_exam) {
this.$('input.practice_exam').prop('checked', true);
} else {
this.$('input.proctored_exam').prop('checked', true);
this.$('.field-exam-review-rules').show();
}
} else {
// Since we have an early exit at the top of the method
// if the subsection is not time limited, then
// here we rightfully assume that it just a timed exam
this.$('input.timed_exam').prop('checked', true);
}
},
setExamTime: function(value) {
var time = this.convertTimeLimitMinutesToString(value);
this.$('.field-time-limit input').val(time);
},
setReviewRules: function(value) {
this.$('.field-exam-review-rules textarea').val(value);
},
isValidTimeLimit: function(time_limit) {
var pattern = new RegExp('^\\d{1,2}:[0-5][0-9]$');
return pattern.test(time_limit) && time_limit !== '00:00';
},
getExamTimeLimit: function() {
return this.$('.field-time-limit input').val();
},
convertTimeLimitMinutesToString: function(timeLimitMinutes) {
var hoursStr = '' + Math.floor(timeLimitMinutes / 60);
var actualMinutesStr = '' + (timeLimitMinutes % 60);
hoursStr = '00'.substring(0, 2 - hoursStr.length) + hoursStr;
actualMinutesStr = '00'.substring(0, 2 - actualMinutesStr.length) + actualMinutesStr;
return hoursStr + ':' + actualMinutesStr;
},
convertTimeLimitToMinutes: function(time_limit) {
var time = time_limit.split(':');
var total_time = (parseInt(time[0]) * 60) + parseInt(time[1]);
return total_time;
},
getRequestData: function() {
var is_time_limited;
var is_practice_exam;
var is_proctored_exam;
var time_limit = this.getExamTimeLimit();
var exam_review_rules = this.$('.field-exam-review-rules textarea').val();
if (this.$('input.no_special_exam').is(':checked')) {
is_time_limited = false;
is_practice_exam = false;
is_proctored_exam = false;
} else if (this.$('input.timed_exam').is(':checked')) {
is_time_limited = true;
is_practice_exam = false;
is_proctored_exam = false;
} else if (this.$('input.proctored_exam').is(':checked')) {
is_time_limited = true;
is_practice_exam = false;
is_proctored_exam = true;
} else if (this.$('input.practice_exam').is(':checked')) {
is_time_limited = true;
is_practice_exam = true;
is_proctored_exam = true;
}
return {
metadata: {
is_practice_exam: is_practice_exam,
is_time_limited: is_time_limited,
exam_review_rules: exam_review_rules,
// We have to use the legacy field name
// as the Ajax handler directly populates
// the xBlocks fields. We will have to
// update this call site when we migrate
// seq_module.py to use 'is_proctored_exam'
is_proctored_enabled: is_proctored_exam,
default_time_limit_minutes: this.convertTimeLimitToMinutes(time_limit)
}
};
}
});
AccessEditor = AbstractEditor.extend({
templateName: 'access-editor',
className: 'edit-settings-access',
events: {
'change #prereq': 'handlePrereqSelect',
'keyup #prereq_min_completion': 'validateScoreAndCompletion',
'keyup #prereq_min_score': 'validateScoreAndCompletion'
},
afterRender: function() {
AbstractEditor.prototype.afterRender.call(this);
var prereq = this.model.get('prereq') || '';
var prereqMinScore = this.model.get('prereq_min_score') || '100';
var prereqMinCompletion = this.model.get('prereq_min_completion') || '100';
this.$('#is_prereq').prop('checked', this.model.get('is_prereq'));
this.$('#prereq option[value="' + prereq + '"]').prop('selected', true);
this.$('#prereq_min_score').val(prereqMinScore);
this.$('#prereq_min_score_input').toggle(prereq.length > 0);
this.$('#prereq_min_completion').val(prereqMinCompletion);
this.$('#prereq_min_completion_input').toggle(prereq.length > 0);
},
handlePrereqSelect: function() {
var showPrereqInput = this.$('#prereq option:selected').val().length > 0;
this.$('#prereq_min_score_input').toggle(showPrereqInput);
this.$('#prereq_min_completion_input').toggle(showPrereqInput);
},
isValidPercentage: function(val) {
var intVal = parseInt(val, 10);
return (typeof val !== 'undefined' && val !== '' && intVal >= 0 && intVal <= 100 && String(intVal) === val);
},
validateScoreAndCompletion: function() {
var invalidInput = false;
var minScore = this.$('#prereq_min_score').val().trim();
var minCompletion = this.$('#prereq_min_completion').val().trim();
if (minScore === '' || !this.isValidPercentage(minScore)) {
invalidInput = true;
this.$('#prereq_min_score_error').show();
} else {
this.$('#prereq_min_score_error').hide();
}
if (minCompletion === '' || !this.isValidPercentage(minCompletion)) {
invalidInput = true;
this.$('#prereq_min_completion_error').show();
} else {
this.$('#prereq_min_completion_error').hide();
}
if (invalidInput) {
BaseModal.prototype.disableActionButton.call(this.parent, 'save');
} else {
BaseModal.prototype.enableActionButton.call(this.parent, 'save');
}
},
getRequestData: function() {
var minScore = this.$('#prereq_min_score').val();
var minCompletion = this.$('#prereq_min_completion').val();
if (minScore) {
minScore = minScore.trim();
}
if (minCompletion) {
minCompletion = minCompletion.trim();
}
return {
isPrereq: this.$('#is_prereq').is(':checked'),
prereqUsageKey: this.$('#prereq option:selected').val(),
prereqMinScore: minScore,
prereqMinCompletion: minCompletion
};
}
});
GradingEditor = AbstractEditor.extend({
templateName: 'grading-editor',
className: 'edit-settings-grading',
afterRender: function() {
AbstractEditor.prototype.afterRender.call(this);
this.setValue(this.model.get('format') || 'notgraded');
},
setValue: function(value) {
this.$('#grading_type').val(value);
},
getValue: function() {
return this.$('#grading_type').val();
},
getRequestData: function() {
return {
graderType: this.getValue()
};
},
getContext: function() {
return {
graderTypes: this.model.get('course_graders')
};
}
});
PublishEditor = AbstractEditor.extend({
templateName: 'publish-editor',
className: 'edit-settings-publish',
getRequestData: function() {
return {
publish: 'make_public'
};
}
});
AbstractVisibilityEditor = AbstractEditor.extend({
afterRender: function() {
AbstractEditor.prototype.afterRender.call(this);
},
isModelLocked: function() {
return this.model.get('has_explicit_staff_lock');
},
isAncestorLocked: function() {
return this.model.get('ancestor_has_staff_lock');
},
getContext: function() {
return {
hasExplicitStaffLock: this.isModelLocked(),
ancestorLocked: this.isAncestorLocked()
};
}
});
StaffLockEditor = AbstractVisibilityEditor.extend({
templateName: 'staff-lock-editor',
className: 'edit-staff-lock',
afterRender: function() {
AbstractVisibilityEditor.prototype.afterRender.call(this);
this.setLock(this.isModelLocked());
},
setLock: function(value) {
this.$('#staff_lock').prop('checked', value);
},
isLocked: function() {
return this.$('#staff_lock').is(':checked');
},
hasChanges: function() {
return this.isModelLocked() !== this.isLocked();
},
getRequestData: function() {
if (this.hasChanges()) {
return {
publish: 'republish',
metadata: {
visible_to_staff_only: this.isLocked() ? true : null
}
};
} else {
return {};
}
}
});
UnitAccessEditor = AbstractVisibilityEditor.extend({
templateName: 'unit-access-editor',
className: 'edit-unit-access',
events: {
'change .user-partition-select': function() {
this.hideCheckboxDivs();
this.showSelectedDiv(this.getSelectedEnrollmentTrackId());
}
},
afterRender: function() {
var groupAccess,
keys;
AbstractVisibilityEditor.prototype.afterRender.call(this);
this.hideCheckboxDivs();
if (this.model.attributes.group_access) {
groupAccess = this.model.attributes.group_access;
keys = Object.keys(groupAccess);
if (keys.length === 1) { // should be only one partition key
if (groupAccess.hasOwnProperty(keys[0]) && groupAccess[keys[0]].length > 0) {
// Select the option that has group access, provided there is a specific group within the scheme
this.$('.user-partition-select option[value=' + keys[0] + ']').prop('selected', true);
this.showSelectedDiv(keys[0]);
// Change default option to 'All Learners and Staff' if unit is currently restricted
this.$('#partition-select option:first').text(gettext('All Learners and Staff'));
}
}
}
},
getSelectedEnrollmentTrackId: function() {
return parseInt(this.$('.user-partition-select').val(), 10);
},
getCheckboxDivs: function() {
return $('.user-partition-group-checkboxes').children('div');
},
getSelectedCheckboxesByDivId: function(contentGroupId) {
var $checkboxes = $('#' + contentGroupId + '-checkboxes input:checked'),
selectedCheckboxValues = [],
i;
for (i = 0; i < $checkboxes.length; i++) {
selectedCheckboxValues.push(parseInt($($checkboxes[i]).val(), 10));
}
return selectedCheckboxValues;
},
showSelectedDiv: function(contentGroupId) {
$('#' + contentGroupId + '-checkboxes').show();
},
hideCheckboxDivs: function() {
this.getCheckboxDivs().hide();
},
hasChanges: function() {
// compare the group access object retrieved vs the current selection
return (JSON.stringify(this.model.get('group_access')) !== JSON.stringify(this.getGroupAccessData()));
},
getGroupAccessData: function() {
var userPartitionId = this.getSelectedEnrollmentTrackId(),
groupAccess = {};
if (userPartitionId !== -1 && !isNaN(userPartitionId)) {
groupAccess[userPartitionId] = this.getSelectedCheckboxesByDivId(userPartitionId);
return groupAccess;
} else {
return {};
}
},
getRequestData: function() {
var metadata = {},
groupAccessData = this.getGroupAccessData();
if (this.hasChanges()) {
if (groupAccessData) {
metadata.group_access = groupAccessData;
}
return {
publish: 'republish',
metadata: metadata
};
} else {
return {};
}
}
});
ContentVisibilityEditor = AbstractVisibilityEditor.extend({
templateName: 'content-visibility-editor',
className: 'edit-content-visibility',
events: {
'change input[name=content-visibility]': 'toggleUnlockWarning'
},
modelVisibility: function() {
if (this.model.get('has_explicit_staff_lock')) {
return 'staff_only';
} else if (this.model.get('hide_after_due')) {
return 'hide_after_due';
} else {
return 'visible';
}
},
afterRender: function() {
AbstractVisibilityEditor.prototype.afterRender.call(this);
this.setVisibility(this.modelVisibility());
this.$('input[name=content-visibility]:checked').change();
},
setVisibility: function(value) {
this.$('input[name=content-visibility][value=' + value + ']').prop('checked', true);
},
currentVisibility: function() {
return this.$('input[name=content-visibility]:checked').val();
},
hasChanges: function() {
return this.modelVisibility() !== this.currentVisibility();
},
toggleUnlockWarning: function() {
var warning = this.$('.staff-lock .tip-warning');
if (warning) {
var display;
if (this.currentVisibility() !== 'staff_only') {
display = 'block';
} else {
display = 'none';
}
$.each(warning, function(_, element) {
element.style.display = display;
});
}
},
getRequestData: function() {
if (this.hasChanges()) {
var metadata = {};
if (this.currentVisibility() === 'staff_only') {
metadata.visible_to_staff_only = true;
metadata.hide_after_due = null;
} else if (this.currentVisibility() === 'hide_after_due') {
metadata.visible_to_staff_only = null;
metadata.hide_after_due = true;
} else {
metadata.visible_to_staff_only = null;
metadata.hide_after_due = null;
}
return {
publish: 'republish',
metadata: metadata
};
} else {
return {};
}
},
getContext: function() {
return $.extend(
{},
AbstractVisibilityEditor.prototype.getContext.call(this),
{
hide_after_due: this.modelVisibility() === 'hide_after_due',
self_paced: course.get('self_paced') === true
}
);
}
});
ShowCorrectnessEditor = AbstractEditor.extend({
templateName: 'show-correctness-editor',
className: 'edit-show-correctness',
afterRender: function() {
AbstractEditor.prototype.afterRender.call(this);
this.setValue(this.model.get('show_correctness') || 'always');
},
setValue: function(value) {
this.$('input[name=show-correctness][value=' + value + ']').prop('checked', true);
},
currentValue: function() {
return this.$('input[name=show-correctness]:checked').val();
},
hasChanges: function() {
return this.model.get('show_correctness') !== this.currentValue();
},
getRequestData: function() {
if (this.hasChanges()) {
return {
publish: 'republish',
metadata: {
show_correctness: this.currentValue()
}
};
} else {
return {};
}
},
getContext: function() {
return $.extend(
{},
AbstractEditor.prototype.getContext.call(this),
{
self_paced: course.get('self_paced') === true
}
);
}
});
HighlightsEditor = AbstractEditor.extend({
templateName: 'highlights-editor',
className: 'edit-show-highlights',
currentValue: function() {
var highlights = [];
$('.highlight-input-text').each(function() {
var value = $(this).val();
if (value !== '' && value !== null) {
highlights.push(value);
}
});
return highlights;
},
hasChanges: function() {
return this.model.get('highlights') !== this.currentValue();
},
getRequestData: function() {
if (this.hasChanges()) {
return {
publish: 'republish',
metadata: {
highlights: this.currentValue()
}
};
} else {
return {};
}
},
getContext: function() {
return $.extend(
{},
AbstractEditor.prototype.getContext.call(this),
{
highlights: this.model.get('highlights'),
highlights_preview_only: this.model.get('highlights_preview_only'),
highlights_doc_url: this.model.get('highlights_doc_url')
}
);
}
});
HighlightsEnableEditor = AbstractEditor.extend({
templateName: 'highlights-enable-editor',
className: 'edit-enable-highlights',
currentValue: function() {
return true;
},
hasChanges: function() {
return this.model.get('highlights_enabled_for_messaging') !== this.currentValue();
},
getRequestData: function() {
if (this.hasChanges()) {
return {
publish: 'republish',
metadata: {
highlights_enabled_for_messaging: this.currentValue()
}
};
} else {
return {};
}
},
getContext: function() {
return $.extend(
{},
AbstractEditor.prototype.getContext.call(this),
{
highlights_enabled: this.model.get('highlights_enabled_for_messaging'),
highlights_doc_url: this.model.get('highlights_doc_url')
}
);
}
});
return {
getModal: function(type, xblockInfo, options) {
if (type === 'edit') {
return this.getEditModal(xblockInfo, options);
} else if (type === 'publish') {
return this.getPublishModal(xblockInfo, options);
} else if (type === 'highlights') {
return this.getHighlightsModal(xblockInfo, options);
} else if (type === 'highlights_enable') {
return this.getHighlightsEnableModal(xblockInfo, options);
} else {
return null;
}
},
getEditModal: function(xblockInfo, options) {
var tabs = [];
var editors = [];
var advancedTab = {
name: 'advanced',
displayName: gettext('Advanced'),
editors: []
};
if (xblockInfo.isVertical()) {
editors = [StaffLockEditor, UnitAccessEditor];
} else {
tabs = [
{
name: 'basic',
displayName: gettext('Basic'),
editors: []
},
{
name: 'visibility',
displayName: gettext('Visibility'),
editors: []
}
];
if (xblockInfo.isChapter()) {
tabs[0].editors = [ReleaseDateEditor];
tabs[1].editors = [StaffLockEditor];
} else if (xblockInfo.isSequential()) {
tabs[0].editors = [ReleaseDateEditor, GradingEditor, DueDateEditor];
tabs[1].editors = [ContentVisibilityEditor, ShowCorrectnessEditor];
if (options.enable_proctored_exams || options.enable_timed_exams) {
advancedTab.editors.push(TimedExaminationPreferenceEditor);
}
if (typeof(xblockInfo.get('is_prereq')) !== 'undefined') {
advancedTab.editors.push(AccessEditor);
}
// Show the Advanced tab iff it has editors to display
if (advancedTab.editors.length > 0) {
tabs.push(advancedTab);
}
}
}
/* globals course */
if (course.get('self_paced')) {
editors = _.without(editors, ReleaseDateEditor, DueDateEditor);
_.each(tabs, function(tab) {
tab.editors = _.without(tab.editors, ReleaseDateEditor, DueDateEditor);
});
}
return new SettingsXBlockModal($.extend({
tabs: tabs,
editors: editors,
model: xblockInfo
}, options));
},
getPublishModal: function(xblockInfo, options) {
return new PublishXBlockModal($.extend({
editors: [PublishEditor],
model: xblockInfo
}, options));
},
getHighlightsModal: function(xblockInfo, options) {
return new HighlightsXBlockModal($.extend({
editors: [HighlightsEditor],
model: xblockInfo
}, options));
},
getHighlightsEnableModal: function(xblockInfo, options) {
return new HighlightsEnableXBlockModal($.extend({
editors: [HighlightsEnableEditor],
model: xblockInfo
}, options));
}
};
});