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; } }); } );