ECOM-4904 Move the program editor backbone app to Studio (#12962)
This commit is contained in:
59
cms/static/js/programs/views/confirm_modal_view.js
Normal file
59
cms/static/js/programs/views/confirm_modal_view.js
Normal file
@@ -0,0 +1,59 @@
|
||||
define([
|
||||
'backbone',
|
||||
'jquery',
|
||||
'underscore',
|
||||
'js/programs/utils/constants',
|
||||
'text!templates/programs/confirm_modal.underscore',
|
||||
'edx-ui-toolkit/js/utils/html-utils',
|
||||
'gettext'
|
||||
],
|
||||
function( Backbone, $, _, constants, ModalTpl, HtmlUtils ) {
|
||||
'use strict';
|
||||
|
||||
return Backbone.View.extend({
|
||||
events: {
|
||||
'click .js-cancel': 'destroy',
|
||||
'click .js-confirm': 'confirm',
|
||||
'keydown': 'handleKeydown'
|
||||
},
|
||||
|
||||
tpl: HtmlUtils.template( ModalTpl ),
|
||||
|
||||
initialize: function( options ) {
|
||||
this.$parentEl = $( options.parentEl );
|
||||
this.callback = options.callback;
|
||||
this.content = options.content;
|
||||
this.render();
|
||||
},
|
||||
|
||||
render: function() {
|
||||
HtmlUtils.setHtml(this.$el, this.tpl( this.content ));
|
||||
HtmlUtils.setHtml(this.$parentEl, HtmlUtils.HTML(this.$el));
|
||||
this.postRender();
|
||||
},
|
||||
|
||||
postRender: function() {
|
||||
this.$el.find('.js-focus-first').focus();
|
||||
},
|
||||
|
||||
confirm: function() {
|
||||
this.callback();
|
||||
this.destroy();
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this.undelegateEvents();
|
||||
this.remove();
|
||||
this.$parentEl.html('');
|
||||
},
|
||||
|
||||
handleKeydown: function( event ) {
|
||||
var keyCode = event.keyCode;
|
||||
|
||||
if ( keyCode === constants.keyCodes.esc ) {
|
||||
this.destroy();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
204
cms/static/js/programs/views/course_details_view.js
Normal file
204
cms/static/js/programs/views/course_details_view.js
Normal file
@@ -0,0 +1,204 @@
|
||||
define([
|
||||
'backbone',
|
||||
'backbone.validation',
|
||||
'jquery',
|
||||
'underscore',
|
||||
'js/programs/models/course_model',
|
||||
'js/programs/models/course_run_model',
|
||||
'js/programs/models/program_model',
|
||||
'js/programs/views/course_run_view',
|
||||
'text!templates/programs/course_details.underscore',
|
||||
'edx-ui-toolkit/js/utils/html-utils',
|
||||
'gettext',
|
||||
'js/programs/utils/validation_config'
|
||||
],
|
||||
function( Backbone, BackboneValidation, $, _, CourseModel, CourseRunModel,
|
||||
ProgramModel, CourseRunView, ListTpl, HtmlUtils ) {
|
||||
'use strict';
|
||||
|
||||
return Backbone.View.extend({
|
||||
parentEl: '.js-course-list',
|
||||
|
||||
className: 'course-details',
|
||||
|
||||
events: {
|
||||
'click .js-remove-course': 'destroy',
|
||||
'click .js-select-course': 'setCourse',
|
||||
'click .js-add-course-run': 'addCourseRun'
|
||||
},
|
||||
|
||||
tpl: HtmlUtils.template( ListTpl ),
|
||||
|
||||
initialize: function( options ) {
|
||||
this.model = new CourseModel();
|
||||
Backbone.Validation.bind( this );
|
||||
this.$parentEl = $( this.parentEl );
|
||||
|
||||
// For managing subViews
|
||||
this.courseRunViews = [];
|
||||
this.courseRuns = options.courseRuns;
|
||||
this.programModel = options.programModel;
|
||||
|
||||
if ( options.courseData ) {
|
||||
this.model.set(options.courseData);
|
||||
} else {
|
||||
this.model.set({run_modes: []});
|
||||
}
|
||||
|
||||
// Need a unique value for field ids so using model cid
|
||||
this.model.set({cid: this.model.cid});
|
||||
this.model.on('change:run_modes', this.updateRuns, this);
|
||||
this.render();
|
||||
},
|
||||
|
||||
render: function() {
|
||||
HtmlUtils.setHtml(this.$el, this.tpl(this.formatData()));
|
||||
this.$parentEl.append( this.$el );
|
||||
this.postRender();
|
||||
},
|
||||
|
||||
postRender: function() {
|
||||
var runs = this.model.get('run_modes');
|
||||
if ( runs && runs.length > 0 ) {
|
||||
this.addCourseRuns();
|
||||
}
|
||||
},
|
||||
|
||||
addCourseRun: function(event) {
|
||||
var $runsContainer = this.$el.find('.js-course-runs'),
|
||||
runModel = new CourseRunModel(),
|
||||
runView;
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
runModel.set({course_key: undefined});
|
||||
|
||||
runView = new CourseRunView({
|
||||
model: runModel,
|
||||
courseModel: this.model,
|
||||
courseRuns: this.courseRuns,
|
||||
programStatus: this.programModel.get('status'),
|
||||
$parentEl: $runsContainer
|
||||
});
|
||||
|
||||
this.courseRunViews.push( runView );
|
||||
},
|
||||
|
||||
addCourseRuns: function() {
|
||||
// Create run views
|
||||
var runs = this.model.get('run_modes'),
|
||||
$runsContainer = this.$el.find('.js-course-runs');
|
||||
|
||||
_.each( runs, function( run ) {
|
||||
var runModel = new CourseRunModel(),
|
||||
runView;
|
||||
|
||||
runModel.set(run);
|
||||
|
||||
runView = new CourseRunView({
|
||||
model: runModel,
|
||||
courseModel: this.model,
|
||||
courseRuns: this.courseRuns,
|
||||
programStatus: this.programModel.get('status'),
|
||||
$parentEl: $runsContainer
|
||||
});
|
||||
|
||||
this.courseRunViews.push( runView );
|
||||
|
||||
return runView;
|
||||
}.bind(this) );
|
||||
},
|
||||
|
||||
addCourseToProgram: function() {
|
||||
var courseCodes = this.programModel.get('course_codes'),
|
||||
courseData = this.model.toJSON();
|
||||
|
||||
if ( this.programModel.isValid( true ) ) {
|
||||
// We don't want to save the cid so omit it
|
||||
courseCodes.push( _.omit(courseData, 'cid') );
|
||||
this.programModel.patch({ course_codes: courseCodes });
|
||||
}
|
||||
},
|
||||
// Delete this view
|
||||
destroy: function() {
|
||||
Backbone.Validation.unbind(this);
|
||||
this.destroyChildren();
|
||||
this.undelegateEvents();
|
||||
this.removeCourseFromProgram();
|
||||
this.remove();
|
||||
},
|
||||
|
||||
destroyChildren: function() {
|
||||
var runs = this.courseRunViews;
|
||||
|
||||
_.each( runs, function( run ) {
|
||||
run.removeRun();
|
||||
});
|
||||
},
|
||||
|
||||
// Format data to be passed to the template
|
||||
formatData: function() {
|
||||
var data = $.extend( {},
|
||||
{ courseRuns: this.courseRuns.models },
|
||||
_.omit( this.programModel.toJSON(), 'run_modes'),
|
||||
this.model.toJSON()
|
||||
);
|
||||
|
||||
return data;
|
||||
},
|
||||
|
||||
removeCourseFromProgram: function() {
|
||||
var courseCodes = this.programModel.get('course_codes'),
|
||||
key = this.model.get('key'),
|
||||
name = this.model.get('display_name'),
|
||||
update = [];
|
||||
|
||||
update = _.reject( courseCodes, function(course) {
|
||||
return course.key === key && course.display_name === name;
|
||||
});
|
||||
|
||||
this.programModel.patch({ course_codes: update });
|
||||
},
|
||||
|
||||
setCourse: function( event ) {
|
||||
var $form = this.$('.js-course-form'),
|
||||
title = $form.find('.display-name').val(),
|
||||
key = $form.find('.course-key').val();
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
this.model.set({
|
||||
display_name: title,
|
||||
key: key,
|
||||
organization: this.programModel.get('organizations')[0]
|
||||
});
|
||||
|
||||
if ( this.model.isValid(true) ) {
|
||||
this.addCourseToProgram();
|
||||
this.updateDOM();
|
||||
this.addCourseRuns();
|
||||
}
|
||||
},
|
||||
|
||||
updateDOM: function() {
|
||||
HtmlUtils.setHtml(this.$el, this.tpl( this.formatData() ) );
|
||||
},
|
||||
|
||||
updateRuns: function() {
|
||||
var courseCodes = this.programModel.get('course_codes'),
|
||||
key = this.model.get('key'),
|
||||
name = this.model.get('display_name'),
|
||||
index;
|
||||
|
||||
if ( this.programModel.isValid( true ) ) {
|
||||
index = _.findIndex( courseCodes, function(course) {
|
||||
return course.key === key && course.display_name === name;
|
||||
});
|
||||
courseCodes[index] = this.model.toJSON();
|
||||
|
||||
this.programModel.patch({ course_codes: courseCodes });
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
113
cms/static/js/programs/views/course_run_view.js
Normal file
113
cms/static/js/programs/views/course_run_view.js
Normal file
@@ -0,0 +1,113 @@
|
||||
define([
|
||||
'backbone',
|
||||
'jquery',
|
||||
'underscore',
|
||||
'text!templates/programs/course_run.underscore',
|
||||
'edx-ui-toolkit/js/utils/html-utils'
|
||||
],
|
||||
function ( Backbone, $, _, CourseRunTpl, HtmlUtils ) {
|
||||
'use strict';
|
||||
|
||||
return Backbone.View.extend({
|
||||
events: {
|
||||
'change .js-course-run-select': 'selectRun',
|
||||
'click .js-remove-run': 'removeRun'
|
||||
},
|
||||
|
||||
tpl: HtmlUtils.template( CourseRunTpl ),
|
||||
|
||||
initialize: function( options ) {
|
||||
/**
|
||||
* Need the run model for the template, and the courseModel
|
||||
* to keep parent view up to date with run changes
|
||||
*/
|
||||
this.courseModel = options.courseModel;
|
||||
this.courseRuns = options.courseRuns;
|
||||
this.programStatus = options.programStatus;
|
||||
|
||||
this.model.on('change', this.render, this);
|
||||
this.courseRuns.on('update', this.updateDropdown, this);
|
||||
|
||||
this.$parentEl = options.$parentEl;
|
||||
this.render();
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var data = this.model.attributes;
|
||||
|
||||
data.programStatus = this.programStatus;
|
||||
|
||||
if ( !!this.courseRuns ) {
|
||||
data.courseRuns = this.courseRuns.toJSON();
|
||||
}
|
||||
|
||||
HtmlUtils.setHtml(this.$el, this.tpl( data ) );
|
||||
this.$parentEl.append( this.$el );
|
||||
},
|
||||
|
||||
// Delete this view
|
||||
destroy: function() {
|
||||
this.undelegateEvents();
|
||||
this.remove();
|
||||
},
|
||||
|
||||
// Data returned from courseList API is not the correct format
|
||||
formatData: function( data ) {
|
||||
return {
|
||||
course_key: data.id,
|
||||
mode_slug: 'verified',
|
||||
start_date: data.start,
|
||||
sku: ''
|
||||
};
|
||||
},
|
||||
|
||||
removeRun: function() {
|
||||
// Update run_modes array on programModel
|
||||
var startDate = this.model.get('start_date'),
|
||||
courseKey = this.model.get('course_key'),
|
||||
/**
|
||||
* NB: cloning the array so the model will fire a change event when
|
||||
* the updated version is saved back to the model
|
||||
*/
|
||||
runs = _.clone(this.courseModel.get('run_modes')),
|
||||
updatedRuns = [];
|
||||
|
||||
updatedRuns = _.reject( runs, function( obj ) {
|
||||
return obj.start_date === startDate &&
|
||||
obj.course_key === courseKey;
|
||||
});
|
||||
|
||||
this.courseModel.set({
|
||||
run_modes: updatedRuns
|
||||
});
|
||||
|
||||
this.courseRuns.addRun(courseKey);
|
||||
|
||||
this.destroy();
|
||||
},
|
||||
|
||||
selectRun: function(event) {
|
||||
var id = $(event.currentTarget).val(),
|
||||
runObj = _.findWhere(this.courseRuns.allRuns, {id: id}),
|
||||
/**
|
||||
* NB: cloning the array so the model will fire a change event when
|
||||
* the updated version is saved back to the model
|
||||
*/
|
||||
runs = _.clone(this.courseModel.get('run_modes')),
|
||||
data = this.formatData(runObj);
|
||||
|
||||
this.model.set( data );
|
||||
runs.push(data);
|
||||
this.courseModel.set({run_modes: runs});
|
||||
this.courseRuns.removeRun(id);
|
||||
},
|
||||
|
||||
// If a run has not been selected update the dropdown options
|
||||
updateDropdown: function() {
|
||||
if ( !this.model.get('course_key') ) {
|
||||
this.render();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
68
cms/static/js/programs/views/program_admin_app_view.js
Normal file
68
cms/static/js/programs/views/program_admin_app_view.js
Normal file
@@ -0,0 +1,68 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
define([
|
||||
'backbone',
|
||||
'js/programs/router',
|
||||
'js/programs/utils/api_config'
|
||||
],
|
||||
function( Backbone, ProgramRouter, apiConfig ) {
|
||||
return Backbone.View.extend({
|
||||
el: '.js-program-admin',
|
||||
|
||||
events: {
|
||||
'click .js-app-click': 'navigate'
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
apiConfig.set({
|
||||
lmsBaseUrl: this.$el.data('lms-base-url'),
|
||||
programsApiUrl: this.$el.data('programs-api-url'),
|
||||
authUrl: this.$el.data('auth-url'),
|
||||
username: this.$el.data('username')
|
||||
});
|
||||
|
||||
this.app = new ProgramRouter({
|
||||
homeUrl: this.$el.data('home-url')
|
||||
});
|
||||
this.app.start();
|
||||
},
|
||||
|
||||
/**
|
||||
* Navigate to a new page within the app.
|
||||
*
|
||||
* Attempts to open the link in a new tab/window behave as the user expects, however the app
|
||||
* and data will be reloaded in the new tab/window.
|
||||
*
|
||||
* @param {Event} event - Event being handled.
|
||||
* @returns {boolean} - Indicates if event handling succeeded (always true).
|
||||
*/
|
||||
navigate: function (event) {
|
||||
var url = $(event.target).attr('href').replace( this.app.root, '' );
|
||||
|
||||
/**
|
||||
* Handle the cases where the user wants to open the link in a new tab/window.
|
||||
* event.which === 2 checks for the middle mouse button (https://api.jquery.com/event.which/)
|
||||
*/
|
||||
if ( event.ctrlKey || event.shiftKey || event.metaKey || event.which === 2 ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// We'll take it from here...
|
||||
event.preventDefault();
|
||||
|
||||
// Process the navigation in the app/router.
|
||||
if ( url === Backbone.history.getFragment() && url === '' ) {
|
||||
/**
|
||||
* Note: We must call the index directly since Backbone
|
||||
* does not support routing to the same route.
|
||||
*/
|
||||
this.app.index();
|
||||
} else {
|
||||
this.app.navigate( url, { trigger: true } );
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
})();
|
||||
112
cms/static/js/programs/views/program_creator_view.js
Normal file
112
cms/static/js/programs/views/program_creator_view.js
Normal file
@@ -0,0 +1,112 @@
|
||||
define([
|
||||
'backbone',
|
||||
'backbone.validation',
|
||||
'jquery',
|
||||
'underscore',
|
||||
'js/programs/models/organizations_model',
|
||||
'js/programs/models/program_model',
|
||||
'text!templates/programs/program_creator_form.underscore',
|
||||
'edx-ui-toolkit/js/utils/html-utils',
|
||||
'gettext',
|
||||
'js/programs/utils/validation_config'
|
||||
],
|
||||
function ( Backbone, BackboneValidation, $, _, OrganizationsModel, ProgramModel, ListTpl, HtmlUtils ) {
|
||||
'use strict';
|
||||
|
||||
return Backbone.View.extend({
|
||||
parentEl: '.js-program-admin',
|
||||
|
||||
events: {
|
||||
'click .js-create-program': 'createProgram',
|
||||
'click .js-abort-view': 'abort'
|
||||
},
|
||||
|
||||
tpl: HtmlUtils.template( ListTpl ),
|
||||
|
||||
initialize: function( options ) {
|
||||
this.$parentEl = $( this.parentEl );
|
||||
|
||||
this.model = new ProgramModel();
|
||||
this.model.on( 'sync', this.saveSuccess, this );
|
||||
this.model.on( 'error', this.saveError, this );
|
||||
|
||||
// Hook up validation.
|
||||
// See: http://thedersen.com/projects/backbone-validation/#validation-binding.
|
||||
Backbone.Validation.bind( this );
|
||||
|
||||
this.organizations = new OrganizationsModel();
|
||||
this.organizations.on( 'sync', this.render, this );
|
||||
this.organizations.fetch();
|
||||
|
||||
this.router = options.router;
|
||||
},
|
||||
|
||||
render: function() {
|
||||
HtmlUtils.setHtml(
|
||||
this.$el,
|
||||
this.tpl( {
|
||||
orgs: this.organizations.get('results')
|
||||
})
|
||||
);
|
||||
|
||||
HtmlUtils.setHtml(this.$parentEl, HtmlUtils.HTML( this.$el ));
|
||||
},
|
||||
|
||||
abort: function( event ) {
|
||||
event.preventDefault();
|
||||
this.router.goHome();
|
||||
},
|
||||
|
||||
createProgram: function( event ) {
|
||||
var data = this.getData();
|
||||
|
||||
event.preventDefault();
|
||||
this.model.set( data );
|
||||
|
||||
// Check if the model is valid before saving. Invalid attributes are looked
|
||||
// up by name. The corresponding elements receieve an `invalid` class and a
|
||||
// `data-error` attribute. Both are removed when formerly invalid attributes
|
||||
// become valid.
|
||||
// See: http://thedersen.com/projects/backbone-validation/#isvalid.
|
||||
if ( this.model.isValid(true) ) {
|
||||
this.model.save();
|
||||
}
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
// Unhook validation.
|
||||
// See: http://thedersen.com/projects/backbone-validation/#unbinding.
|
||||
Backbone.Validation.unbind(this);
|
||||
|
||||
this.undelegateEvents();
|
||||
this.remove();
|
||||
},
|
||||
|
||||
getData: function() {
|
||||
return {
|
||||
name: this.$el.find( '.program-name' ).val(),
|
||||
subtitle: this.$el.find( '.program-subtitle' ).val(),
|
||||
category: this.$el.find( '.program-type' ).val(),
|
||||
marketing_slug: this.$el.find( '.program-marketing-slug' ).val(),
|
||||
organizations: [{
|
||||
key: this.$el.find( '.program-org' ).val()
|
||||
}]
|
||||
};
|
||||
},
|
||||
|
||||
goToView: function( uri ) {
|
||||
Backbone.history.navigate( uri, { trigger: true } );
|
||||
this.destroy();
|
||||
},
|
||||
|
||||
// TODO: add user messaging to show errors
|
||||
saveError: function( jqXHR ) {
|
||||
console.log( 'saveError: ', jqXHR );
|
||||
},
|
||||
|
||||
saveSuccess: function() {
|
||||
this.goToView( String( this.model.get( 'id' ) ) );
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
207
cms/static/js/programs/views/program_details_view.js
Normal file
207
cms/static/js/programs/views/program_details_view.js
Normal file
@@ -0,0 +1,207 @@
|
||||
define([
|
||||
'backbone',
|
||||
'backbone.validation',
|
||||
'jquery',
|
||||
'underscore',
|
||||
'js/programs/collections/course_runs_collection',
|
||||
'js/programs/models/program_model',
|
||||
'js/programs/views/confirm_modal_view',
|
||||
'js/programs/views/course_details_view',
|
||||
'text!templates/programs/program_details.underscore',
|
||||
'edx-ui-toolkit/js/utils/html-utils',
|
||||
'gettext',
|
||||
'js/programs/utils/validation_config'
|
||||
],
|
||||
function( Backbone, BackboneValidation, $, _, CourseRunsCollection,
|
||||
ProgramModel, ModalView, CourseView, ListTpl,
|
||||
HtmlUtils ) {
|
||||
'use strict';
|
||||
|
||||
return Backbone.View.extend({
|
||||
el: '.js-program-admin',
|
||||
|
||||
events: {
|
||||
'blur .js-inline-edit input': 'checkEdit',
|
||||
'click .js-add-course': 'addCourse',
|
||||
'click .js-enable-edit': 'editField',
|
||||
'click .js-publish-program': 'confirmPublish'
|
||||
},
|
||||
|
||||
tpl: HtmlUtils.template( ListTpl ),
|
||||
|
||||
initialize: function() {
|
||||
Backbone.Validation.bind( this );
|
||||
|
||||
this.courseRuns = new CourseRunsCollection([], {
|
||||
organization: this.model.get('organizations')[0]
|
||||
});
|
||||
this.courseRuns.fetch();
|
||||
this.courseRuns.on('sync', this.setAvailableCourseRuns, this);
|
||||
this.render();
|
||||
},
|
||||
|
||||
render: function() {
|
||||
HtmlUtils.setHtml(this.$el, this.tpl( this.model.toJSON() ) );
|
||||
this.postRender();
|
||||
},
|
||||
|
||||
postRender: function() {
|
||||
var courses = this.model.get( 'course_codes' );
|
||||
|
||||
_.each( courses, function( course ) {
|
||||
var title = course.key + 'Course';
|
||||
|
||||
this[ title ] = new CourseView({
|
||||
courseRuns: this.courseRuns,
|
||||
programModel: this.model,
|
||||
courseData: course
|
||||
});
|
||||
}.bind(this) );
|
||||
|
||||
// Stop listening to the model sync set when publishing
|
||||
this.model.off( 'sync' );
|
||||
},
|
||||
|
||||
addCourse: function() {
|
||||
return new CourseView({
|
||||
courseRuns: this.courseRuns,
|
||||
programModel: this.model
|
||||
});
|
||||
},
|
||||
|
||||
checkEdit: function( event ) {
|
||||
var $input = $(event.target),
|
||||
$span = $input.prevAll('.js-model-value'),
|
||||
$btn = $input.next('.js-enable-edit'),
|
||||
value = $input.val(),
|
||||
key = $input.data('field'),
|
||||
data = {};
|
||||
|
||||
data[key] = value;
|
||||
|
||||
$input.addClass('is-hidden');
|
||||
$btn.removeClass('is-hidden');
|
||||
$span.removeClass('is-hidden');
|
||||
|
||||
if ( this.model.get( key ) !== value ) {
|
||||
this.model.set( data );
|
||||
|
||||
if ( this.model.isValid( true ) ) {
|
||||
this.model.patch( data );
|
||||
$span.text( value );
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Loads modal that user clicks a confirmation button
|
||||
* in to publish the course (or they can cancel out of it)
|
||||
*/
|
||||
confirmPublish: function( event ) {
|
||||
event.preventDefault();
|
||||
|
||||
/**
|
||||
* Update validation to make marketing slug required
|
||||
* Note that because this validation is not required for
|
||||
* the program creation form and is only happening here
|
||||
* it makes sense to have the validation at the view level
|
||||
*/
|
||||
if ( this.model.isValid( true ) && this.validateMarketingSlug() ) {
|
||||
this.modalView = new ModalView({
|
||||
model: this.model,
|
||||
callback: _.bind( this.publishProgram, this ),
|
||||
content: this.getModalContent(),
|
||||
parentEl: '.js-publish-modal',
|
||||
parentView: this
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
editField: function( event ) {
|
||||
/**
|
||||
* Making the assumption that users can only see
|
||||
* programs that they have permission to edit
|
||||
*/
|
||||
var $btn = $( event.currentTarget ),
|
||||
$el = $btn.prev( 'input' );
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
$el.prevAll( '.js-model-value' ).addClass( 'is-hidden' );
|
||||
$el.removeClass( 'is-hidden' )
|
||||
.addClass( 'edit' )
|
||||
.focus();
|
||||
$btn.addClass( 'is-hidden' );
|
||||
},
|
||||
|
||||
getModalContent: function() {
|
||||
/* jshint maxlen: 300 */
|
||||
return {
|
||||
name: gettext('confirm'),
|
||||
title: gettext('Publish this program?'),
|
||||
body: gettext(
|
||||
'After you publish this program, you cannot add or remove course codes or remove course runs.'
|
||||
),
|
||||
cta: {
|
||||
cancel: gettext('Cancel'),
|
||||
confirm: gettext('Publish')
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
publishProgram: function() {
|
||||
var data = {
|
||||
status: 'active'
|
||||
};
|
||||
|
||||
this.model.set( data, { silent: true } );
|
||||
this.model.on( 'sync', this.render, this );
|
||||
this.model.patch( data );
|
||||
},
|
||||
|
||||
setAvailableCourseRuns: function() {
|
||||
var allRuns = this.courseRuns.toJSON(),
|
||||
courses = this.model.get('course_codes'),
|
||||
selectedRuns,
|
||||
availableRuns = allRuns;
|
||||
|
||||
if (courses.length) {
|
||||
selectedRuns = _.pluck( courses, 'run_modes' );
|
||||
selectedRuns = _.flatten( selectedRuns );
|
||||
}
|
||||
|
||||
availableRuns = _.reject(allRuns, function(run) {
|
||||
var selectedCourseRun = _.findWhere( selectedRuns, {
|
||||
course_key: run.id,
|
||||
start_date: run.start
|
||||
});
|
||||
|
||||
return !_.isUndefined(selectedCourseRun);
|
||||
});
|
||||
|
||||
this.courseRuns.set(availableRuns);
|
||||
},
|
||||
|
||||
validateMarketingSlug: function() {
|
||||
var isValid = false,
|
||||
$input = {},
|
||||
$message = {};
|
||||
|
||||
if ( this.model.get( 'marketing_slug' ).length > 0 ) {
|
||||
isValid = true;
|
||||
} else {
|
||||
$input = this.$el.find( '#program-marketing-slug' );
|
||||
$message = $input.siblings( '.field-message' );
|
||||
|
||||
// Update DOM
|
||||
$input.addClass( 'has-error' );
|
||||
$message.addClass( 'has-error' );
|
||||
$message.find( '.field-message-content' )
|
||||
.text( gettext( 'Marketing Slug is required.') );
|
||||
}
|
||||
|
||||
return isValid;
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
Reference in New Issue
Block a user