Commit d43e915d by Brian Jacobel

Run eslint autofixer on /cms

parent c7042c48
......@@ -16,7 +16,7 @@
var getModulesList = function(modules) {
var result = [getModule(commonLibrariesPath)];
return result.concat(modules.map(function (moduleName) {
return result.concat(modules.map(function(moduleName) {
return getModule(moduleName, true);
}));
};
......@@ -171,4 +171,5 @@
*/
logLevel: 1
};
}())
}()) // eslint-disable-line semi
// A semicolon on the line above will break the requirejs optimizer
;(function(require, define) {
(function(require, define) {
'use strict';
if (window) {
......@@ -210,12 +210,12 @@
window.MathJax.Hub.Config({
tex2jax: {
inlineMath: [
['\\(','\\)'],
['[mathjaxinline]','[/mathjaxinline]']
['\\(', '\\)'],
['[mathjaxinline]', '[/mathjaxinline]']
],
displayMath: [
['\\[','\\]'],
['[mathjax]','[/mathjax]']
['\\[', '\\]'],
['[mathjax]', '[/mathjax]']
]
}
});
......
......@@ -2,81 +2,81 @@
(function(sandbox) {
'use strict';
require(["jquery", "backbone", "cms/js/main", "edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers", "jquery.cookie"],
require(['jquery', 'backbone', 'cms/js/main', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers', 'jquery.cookie'],
function($, Backbone, main, AjaxHelpers) {
describe("CMS", function() {
it("should initialize URL", function() {
expect(window.CMS.URL).toBeDefined();
});
});
describe("main helper", function() {
beforeEach(function() {
this.previousAjaxSettings = $.extend(true, {}, $.ajaxSettings);
spyOn($, "cookie").and.callFake(function(param) {
if (param === "csrftoken") {
return "stubCSRFToken";
}
describe('CMS', function() {
it('should initialize URL', function() {
expect(window.CMS.URL).toBeDefined();
});
});
return main();
});
afterEach(function() {
$.ajaxSettings = this.previousAjaxSettings;
return $.ajaxSettings;
});
it("turn on Backbone emulateHTTP", function() {
expect(Backbone.emulateHTTP).toBeTruthy();
});
it("setup AJAX CSRF token", function() {
expect($.ajaxSettings.headers["X-CSRFToken"]).toEqual("stubCSRFToken");
});
});
describe("AJAX Errors", function() {
var server;
server = null;
beforeEach(function() {
appendSetFixtures(sandbox({
id: "page-notification"
}));
});
afterEach(function() {
return server && server.restore();
});
it("successful AJAX request does not pop an error notification", function() {
server = AjaxHelpers.server([
200, {
"Content-Type": "application/json"
}, "{}"
]);
expect($("#page-notification")).toBeEmpty();
$.ajax("/test");
expect($("#page-notification")).toBeEmpty();
server.respond();
expect($("#page-notification")).toBeEmpty();
});
it("AJAX request with error should pop an error notification", function() {
server = AjaxHelpers.server([
500, {
"Content-Type": "application/json"
}, "{}"
]);
$.ajax("/test");
server.respond();
expect($("#page-notification")).not.toBeEmpty();
expect($("#page-notification")).toContainElement('div.wrapper-notification-error');
});
it("can override AJAX request with error so it does not pop an error notification", function() {
server = AjaxHelpers.server([
500, {
"Content-Type": "application/json"
}, "{}"
]);
$.ajax({
url: "/test",
notifyOnError: false
describe('main helper', function() {
beforeEach(function() {
this.previousAjaxSettings = $.extend(true, {}, $.ajaxSettings);
spyOn($, 'cookie').and.callFake(function(param) {
if (param === 'csrftoken') {
return 'stubCSRFToken';
}
});
return main();
});
afterEach(function() {
$.ajaxSettings = this.previousAjaxSettings;
return $.ajaxSettings;
});
it('turn on Backbone emulateHTTP', function() {
expect(Backbone.emulateHTTP).toBeTruthy();
});
it('setup AJAX CSRF token', function() {
expect($.ajaxSettings.headers['X-CSRFToken']).toEqual('stubCSRFToken');
});
});
describe('AJAX Errors', function() {
var server;
server = null;
beforeEach(function() {
appendSetFixtures(sandbox({
id: 'page-notification'
}));
});
afterEach(function() {
return server && server.restore();
});
it('successful AJAX request does not pop an error notification', function() {
server = AjaxHelpers.server([
200, {
'Content-Type': 'application/json'
}, '{}'
]);
expect($('#page-notification')).toBeEmpty();
$.ajax('/test');
expect($('#page-notification')).toBeEmpty();
server.respond();
expect($('#page-notification')).toBeEmpty();
});
it('AJAX request with error should pop an error notification', function() {
server = AjaxHelpers.server([
500, {
'Content-Type': 'application/json'
}, '{}'
]);
$.ajax('/test');
server.respond();
expect($('#page-notification')).not.toBeEmpty();
expect($('#page-notification')).toContainElement('div.wrapper-notification-error');
});
it('can override AJAX request with error so it does not pop an error notification', function() {
server = AjaxHelpers.server([
500, {
'Content-Type': 'application/json'
}, '{}'
]);
$.ajax({
url: '/test',
notifyOnError: false
});
server.respond();
expect($('#page-notification')).toBeEmpty();
});
});
server.respond();
expect($("#page-notification")).toBeEmpty();
});
});
});
}).call(this, sandbox);
......@@ -24,7 +24,6 @@ define(['jquery', 'backbone', 'xblock/runtime.v1', 'URI', 'gettext', 'js/utils/m
StudioRuntime = {};
BaseRuntime.v1 = (function(_super) {
__extends(v1, _super);
v1.prototype.handlerUrl = function(element, handlerName, suffix, query) {
......@@ -150,11 +149,9 @@ define(['jquery', 'backbone', 'xblock/runtime.v1', 'URI', 'gettext', 'js/utils/m
};
return v1;
})(XBlock.Runtime.v1);
PreviewRuntime.v1 = (function(_super) {
__extends(v1, _super);
function v1() {
......@@ -164,11 +161,9 @@ define(['jquery', 'backbone', 'xblock/runtime.v1', 'URI', 'gettext', 'js/utils/m
v1.prototype.handlerPrefix = '/preview/xblock';
return v1;
})(BaseRuntime.v1);
StudioRuntime.v1 = (function(_super) {
__extends(v1, _super);
function v1() {
......@@ -178,7 +173,6 @@ define(['jquery', 'backbone', 'xblock/runtime.v1', 'URI', 'gettext', 'js/utils/m
v1.prototype.handlerPrefix = '/xblock';
return v1;
})(BaseRuntime.v1);
// Install the runtime's into the global namespace
......
require([
"domReady",
"jquery",
"underscore",
"gettext",
"common/js/components/views/feedback_notification",
"common/js/components/views/feedback_prompt",
"js/utils/date_utils",
"js/utils/module",
"js/utils/handle_iframe_binding",
"edx-ui-toolkit/js/dropdown-menu/dropdown-menu-view",
"jquery.ui",
"jquery.leanModal",
"jquery.form",
"jquery.smoothScroll"
],
'domReady',
'jquery',
'underscore',
'gettext',
'common/js/components/views/feedback_notification',
'common/js/components/views/feedback_prompt',
'js/utils/date_utils',
'js/utils/module',
'js/utils/handle_iframe_binding',
'edx-ui-toolkit/js/dropdown-menu/dropdown-menu-view',
'jquery.ui',
'jquery.leanModal',
'jquery.form',
'jquery.smoothScroll'
],
function(
domReady,
$,
......@@ -27,113 +27,110 @@ require([
DropdownMenuView
)
{
var $body;
var $body;
domReady(function() {
var dropdownMenuView;
domReady(function() {
var dropdownMenuView;
$body = $('body');
$body = $('body');
$body.on('click', '.embeddable-xml-input', function() {
$(this).select();
});
$body.on('click', '.embeddable-xml-input', function() {
$(this).select();
});
$body.addClass('js');
$body.addClass('js');
// alerts/notifications - manual close
$('.action-alert-close, .alert.has-actions .nav-actions a').bind('click', hideAlert);
$('.action-notification-close').bind('click', hideNotification);
// alerts/notifications - manual close
$('.action-alert-close, .alert.has-actions .nav-actions a').bind('click', hideAlert);
$('.action-notification-close').bind('click', hideNotification);
// nav - dropdown related
$body.click(function(e) {
$('.nav-dd .nav-item .wrapper-nav-sub').removeClass('is-shown');
$('.nav-dd .nav-item .title').removeClass('is-selected');
});
// nav - dropdown related
$body.click(function(e) {
$('.nav-dd .nav-item .wrapper-nav-sub').removeClass('is-shown');
$('.nav-dd .nav-item .title').removeClass('is-selected');
});
$('.nav-dd .nav-item, .filterable-column .nav-item').click(function(e) {
$('.nav-dd .nav-item, .filterable-column .nav-item').click(function(e) {
$subnav = $(this).find('.wrapper-nav-sub');
$title = $(this).find('.title');
$subnav = $(this).find('.wrapper-nav-sub');
$title = $(this).find('.title');
if ($subnav.hasClass('is-shown')) {
$subnav.removeClass('is-shown');
$title.removeClass('is-selected');
} else {
$('.nav-dd .nav-item .title').removeClass('is-selected');
$('.nav-dd .nav-item .wrapper-nav-sub').removeClass('is-shown');
$title.addClass('is-selected');
$subnav.addClass('is-shown');
if ($subnav.hasClass('is-shown')) {
$subnav.removeClass('is-shown');
$title.removeClass('is-selected');
} else {
$('.nav-dd .nav-item .title').removeClass('is-selected');
$('.nav-dd .nav-item .wrapper-nav-sub').removeClass('is-shown');
$title.addClass('is-selected');
$subnav.addClass('is-shown');
// if propagation is not stopped, the event will bubble up to the
// body element, which will close the dropdown.
e.stopPropagation();
}
});
// general link management - new window/tab
$('a[rel="external"]:not([title])').attr('title', gettext('This link will open in a new browser window/tab'));
$('a[rel="external"]').attr('target', '_blank');
// general link management - lean modal window
$('a[rel="modal"]').attr('title', gettext('This link will open in a modal window')).leanModal({
overlay: 0.50,
closeButton: '.action-modal-close'
});
$('.action-modal-close').click(function(e) {
(e).preventDefault();
});
// general link management - smooth scrolling page links
$('a[rel*="view"][href^="#"]').bind('click', smoothScrollLink);
IframeUtils.iframeBinding();
// disable ajax caching in IE so that backbone fetches work
if ($.browser.msie) {
$.ajaxSetup({ cache: false });
}
//Initiate the edx tool kit dropdown menu
if ($('.js-header-user-menu').length){
dropdownMenuView = new DropdownMenuView({
el: '.js-header-user-menu'
e.stopPropagation();
}
});
// general link management - new window/tab
$('a[rel="external"]:not([title])').attr('title', gettext('This link will open in a new browser window/tab'));
$('a[rel="external"]').attr('target', '_blank');
// general link management - lean modal window
$('a[rel="modal"]').attr('title', gettext('This link will open in a modal window')).leanModal({
overlay: 0.50,
closeButton: '.action-modal-close'
});
$('.action-modal-close').click(function(e) {
(e).preventDefault();
});
// general link management - smooth scrolling page links
$('a[rel*="view"][href^="#"]').bind('click', smoothScrollLink);
IframeUtils.iframeBinding();
// disable ajax caching in IE so that backbone fetches work
if ($.browser.msie) {
$.ajaxSetup({cache: false});
}
// Initiate the edx tool kit dropdown menu
if ($('.js-header-user-menu').length) {
dropdownMenuView = new DropdownMenuView({
el: '.js-header-user-menu'
});
dropdownMenuView.postRender();
}
});
dropdownMenuView.postRender();
}
});
function smoothScrollLink(e) {
(e).preventDefault();
$.smoothScroll({
offset: -200,
easing: 'swing',
speed: 1000,
scrollElement: null,
scrollTarget: $(this).attr('href')
});
}
function smoothScrollTop(e) {
(e).preventDefault();
$.smoothScroll({
offset: -200,
easing: 'swing',
speed: 1000,
scrollElement: null,
scrollTarget: $('#view-top')
});
}
function hideNotification(e) {
(e).preventDefault();
$(this).closest('.wrapper-notification').removeClass('is-shown').addClass('is-hiding').attr('aria-hidden', 'true');
}
function hideAlert(e) {
(e).preventDefault();
$(this).closest('.wrapper-alert').removeClass('is-shown');
}
}); // end require()
function smoothScrollLink(e) {
(e).preventDefault();
$.smoothScroll({
offset: -200,
easing: 'swing',
speed: 1000,
scrollElement: null,
scrollTarget: $(this).attr('href')
});
}
function smoothScrollTop(e) {
(e).preventDefault();
$.smoothScroll({
offset: -200,
easing: 'swing',
speed: 1000,
scrollElement: null,
scrollTarget: $('#view-top')
});
}
function hideNotification(e) {
(e).preventDefault();
$(this).closest('.wrapper-notification').removeClass('is-shown').addClass('is-hiding').attr('aria-hidden', 'true');
}
function hideAlert(e) {
(e).preventDefault();
$(this).closest('.wrapper-alert').removeClass('is-shown');
}
}); // end require()
......@@ -29,7 +29,7 @@ function(Backbone, gettext, Certificate) {
} catch (ex) {
// If it didn't parse, and `certificate_info` is an object then return as it is
// otherwise return empty array
if (typeof certificate_info === 'object'){
if (typeof certificate_info === 'object') {
return_array = certificate_info;
}
else {
......@@ -44,28 +44,28 @@ function(Backbone, gettext, Certificate) {
return return_array;
},
onModelRemoved: function () {
onModelRemoved: function() {
// remove the certificate web preview UI.
if(window.certWebPreview && this.length === 0) {
if (window.certWebPreview && this.length === 0) {
window.certWebPreview.remove();
}
this.toggleAddNewItemButtonState();
},
onModelAdd: function () {
onModelAdd: function() {
this.toggleAddNewItemButtonState();
},
toggleAddNewItemButtonState: function() {
// user can create a new item e.g certificate; if not exceeded the maxAllowed limit.
if(this.length >= this.maxAllowed) {
$(".action-add").addClass('action-add-hidden');
if (this.length >= this.maxAllowed) {
$('.action-add').addClass('action-add-hidden');
} else {
$(".action-add").removeClass('action-add-hidden');
$('.action-add').removeClass('action-add-hidden');
}
},
parse: function (certificatesJson) {
parse: function(certificatesJson) {
// Transforms the provided JSON into a Certificates collection
var modelArray = this.certificate_array(certificatesJson);
......
......@@ -20,7 +20,7 @@ define([
],
function($, CertificatesCollection, Certificate, CertificatesPage, CertificatePreview) {
'use strict';
return function (certificatesJson, certificateUrl, courseOutlineUrl, course_modes, certificate_web_view_url,
return function(certificatesJson, certificateUrl, courseOutlineUrl, course_modes, certificate_web_view_url,
is_active, certificate_activation_handler_url) {
// Initialize the model collection, passing any necessary options to the constructor
var certificatesCollection = new CertificatesCollection(certificatesJson, {
......@@ -31,7 +31,7 @@ function($, CertificatesCollection, Certificate, CertificatesPage, CertificatePr
// associating the certificate_preview globally.
// need to show / hide this view in some other places.
if(!window.certWebPreview && certificate_web_view_url) {
if (!window.certWebPreview && certificate_web_view_url) {
window.certWebPreview = new CertificatePreview({
course_modes: course_modes,
certificate_web_view_url: certificate_web_view_url,
......
// Backbone.js Application Model: Certificate
define([
'underscore',
'backbone',
'backbone-relational',
'backbone.associations',
'gettext',
'cms/js/main',
'js/certificates/models/signatory',
'js/certificates/collections/signatories'
],
'underscore',
'backbone',
'backbone-relational',
'backbone.associations',
'gettext',
'cms/js/main',
'js/certificates/models/signatory',
'js/certificates/collections/signatories'
],
function(_, Backbone, BackboneRelational, BackboneAssociations, gettext, CoffeeSrcMain,
SignatoryModel, SignatoryCollection) {
'use strict';
......@@ -78,7 +78,7 @@ define([
attributes: {name: true}
};
}
var allSignatoriesValid = _.every(attrs.signatories.models, function(signatory){
var allSignatoriesValid = _.every(attrs.signatories.models, function(signatory) {
return signatory.isValid();
});
if (!allSignatoriesValid) {
......
......@@ -3,13 +3,13 @@
define(['jquery'], function($) { // eslint-disable-line no-unused-vars
'use strict';
return function () {
return function() {
jasmine.addMatchers({
toBeCorrectValuesInModel: function () {
toBeCorrectValuesInModel: function() {
// Assert the value being tested has key values which match the provided values
return {
compare: function (actual, values) {
var passed = _.every(values, function (value, key) {
compare: function(actual, values) {
var passed = _.every(values, function(value, key) {
return actual.get(key) === value;
}.bind(this));
......
......@@ -11,7 +11,7 @@ function(CertificateModel, CertificateCollection) {
beforeEach(function() {
this.newModelOptions = {add: true};
this.model = new CertificateModel({editing: true}, this.newModelOptions);
this.collection = new CertificateCollection([ this.model ], {certificateUrl: '/outline'});
this.collection = new CertificateCollection([this.model], {certificateUrl: '/outline'});
});
describe('Basic', function() {
......@@ -39,18 +39,16 @@ function(CertificateModel, CertificateCollection) {
describe('Validation', function() {
it('requires a name', function() {
var model = new CertificateModel({ name: '' }, this.newModelOptions);
var model = new CertificateModel({name: ''}, this.newModelOptions);
expect(model.isValid()).toBeFalsy();
});
it('can pass validation', function() {
var model = new CertificateModel({ name: 'foo' }, this.newModelOptions);
var model = new CertificateModel({name: 'foo'}, this.newModelOptions);
expect(model.isValid()).toBeTruthy();
});
});
});
});
......@@ -41,15 +41,15 @@ function(_, Course, CertificatesCollection, CertificateModel, CertificateDetails
inputSignatoryTitle: '.signatory-title-input',
inputSignatoryOrganization: '.signatory-organization-input'
};
var verifyAndConfirmPrompt = function(promptSpy, promptText){
var verifyAndConfirmPrompt = function(promptSpy, promptText) {
ViewHelpers.verifyPromptShowing(promptSpy, gettext(promptText));
ViewHelpers.confirmPrompt(promptSpy);
ViewHelpers.verifyPromptHidden(promptSpy);
};
describe('Certificate Details Spec:', function() {
var setValuesToInputs = function (view, values) {
_.each(values, function (value, selector) {
var setValuesToInputs = function(view, values) {
_.each(values, function(value, selector) {
if (SELECTORS[selector]) {
view.$(SELECTORS[selector]).val(value);
view.$(SELECTORS[selector]).trigger('change');
......@@ -96,8 +96,8 @@ function(_, Course, CertificatesCollection, CertificateModel, CertificateDetails
is_active: true
}, this.newModelOptions);
this.collection = new CertificatesCollection([ this.model ], {
certificateUrl: '/certificates/'+ window.course.id
this.collection = new CertificatesCollection([this.model], {
certificateUrl: '/certificates/' + window.course.id
});
this.model.set('id', 0);
this.view = new CertificateDetailsView({
......@@ -120,44 +120,43 @@ function(_, Course, CertificatesCollection, CertificateModel, CertificateDetails
describe('The Certificate Details view', function() {
it('should parse a JSON string collection into a Backbone model collection', function () {
var course_title = "Test certificate course title override 2";
it('should parse a JSON string collection into a Backbone model collection', function() {
var course_title = 'Test certificate course title override 2';
var CERTIFICATE_JSON = '[{"course_title": "' + course_title + '", "signatories":"[]"}]';
this.collection.parse(CERTIFICATE_JSON);
var model = this.collection.at(1);
expect(model.get('course_title')).toEqual(course_title);
});
it('should parse a JSON object collection into a Backbone model collection', function () {
var course_title = "Test certificate course title override 2";
it('should parse a JSON object collection into a Backbone model collection', function() {
var course_title = 'Test certificate course title override 2';
var CERTIFICATE_JSON_OBJECT = [{
"course_title" : course_title,
"signatories" : "[]"
'course_title': course_title,
'signatories': '[]'
}];
this.collection.parse(CERTIFICATE_JSON_OBJECT);
var model = this.collection.at(1);
expect(model.get('course_title')).toEqual(course_title);
});
it('should have empty certificate collection if there is an error parsing certifcate JSON', function () {
it('should have empty certificate collection if there is an error parsing certifcate JSON', function() {
var CERTIFICATE_INVALID_JSON = '[{"course_title": Test certificate course title override, "signatories":"[]"}]'; // eslint-disable-line max-len
var collection_length = this.collection.length;
this.collection.parse(CERTIFICATE_INVALID_JSON);
//collection length should remain the same since we have error parsing JSON
// collection length should remain the same since we have error parsing JSON
expect(this.collection.length).toEqual(collection_length);
});
it('should display the certificate course title override', function () {
it('should display the certificate course title override', function() {
expect(this.view.$(SELECTORS.course_title)).toExist();
expect(this.view.$(SELECTORS.course_title)).toContainText('Test Course Title Override');
});
it('should present an Edit action', function () {
it('should present an Edit action', function() {
expect(this.view.$('.edit')).toExist();
});
it('should change to "edit" mode when clicking the Edit button and confirming the prompt', function(){
it('should change to "edit" mode when clicking the Edit button and confirming the prompt', function() {
expect(this.view.$('.action-edit .edit')).toExist();
var promptSpy = ViewHelpers.createPromptSpy();
this.view.$('.action-edit .edit').click();
......@@ -165,67 +164,64 @@ function(_, Course, CertificatesCollection, CertificateModel, CertificateDetails
expect(this.model.get('editing')).toBe(true);
});
it('should not show confirmation prompt when clicked on "edit" in case of inactive certificate', function(){
it('should not show confirmation prompt when clicked on "edit" in case of inactive certificate', function() {
this.model.set('is_active', false);
expect(this.view.$('.action-edit .edit')).toExist();
this.view.$('.action-edit .edit').click();
expect(this.model.get('editing')).toBe(true);
});
it('should not present a Edit action if user is not global staff and certificate is active', function () {
it('should not present a Edit action if user is not global staff and certificate is active', function() {
window.CMS.User = {isGlobalStaff: false};
appendSetFixtures(this.view.render().el);
expect(this.view.$('.action-edit .edit')).not.toExist();
});
it('should present a Delete action', function () {
it('should present a Delete action', function() {
expect(this.view.$('.action-delete .delete')).toExist();
});
it('should not present a Delete action if user is not global staff and certificate is active', function () {
it('should not present a Delete action if user is not global staff and certificate is active', function() {
window.CMS.User = {isGlobalStaff: false};
appendSetFixtures(this.view.render().el);
expect(this.view.$('.action-delete .delete')).not.toExist();
});
it('should prompt the user when when clicking the Delete button', function(){
it('should prompt the user when when clicking the Delete button', function() {
expect(this.view.$('.action-delete .delete')).toExist();
this.view.$('.action-delete .delete').click();
});
it('should scroll to top after rendering if necessary', function () {
it('should scroll to top after rendering if necessary', function() {
$.smoothScroll = jasmine.createSpy('jQuery.smoothScroll');
appendSetFixtures(this.view.render().el);
expect($.smoothScroll).toHaveBeenCalled();
});
});
describe('Signatory details', function(){
describe('Signatory details', function() {
beforeEach(function() {
this.view.render();
});
it('displays certificate signatories details', function(){
it('displays certificate signatories details', function() {
this.view.$('.show-details').click();
expect(this.view.$(SELECTORS.signatory_name_value)).toContainText('');
expect(this.view.$(SELECTORS.signatory_title_value)).toContainText('');
expect(this.view.$(SELECTORS.signatory_organization_value)).toContainText('');
});
it('should present Edit action on signaotry', function () {
it('should present Edit action on signaotry', function() {
expect(this.view.$(SELECTORS.edit_signatory)).toExist();
});
it('should not present Edit action on signaotry if user is not global staff and certificate is active', function () {
it('should not present Edit action on signaotry if user is not global staff and certificate is active', function() {
window.CMS.User = {isGlobalStaff: false};
this.view.render();
expect(this.view.$(SELECTORS.edit_signatory)).not.toExist();
});
it('supports in-line editing of signatory information', function() {
this.view.$(SELECTORS.edit_signatory).click();
expect(this.view.$(SELECTORS.inputSignatoryName)).toExist();
expect(this.view.$(SELECTORS.inputSignatoryTitle)).toExist();
......@@ -233,7 +229,6 @@ function(_, Course, CertificatesCollection, CertificateModel, CertificateDetails
});
it('correctly persists changes made during in-line signatory editing', function() {
var requests = AjaxHelpers.requests(this),
notificationSpy = ViewHelpers.createNotificationSpy();
......
......@@ -37,14 +37,14 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce
note: '.wrapper-delete-button',
addSignatoryButton: '.action-add-signatory',
signatoryDeleteButton: '.signatory-panel-delete',
uploadSignatureButton:'.action-upload-signature',
uploadSignatureButton: '.action-upload-signature',
uploadDialog: 'form.upload-dialog',
uploadDialogButton: '.action-upload',
uploadDialogFileInput: 'form.upload-dialog input[type=file]',
saveCertificateButton: 'button.action-primary'
};
var clickDeleteItem = function (that, promptText, element, url) {
var clickDeleteItem = function(that, promptText, element, url) {
var requests = AjaxHelpers.requests(that),
promptSpy = ViewHelpers.createPromptSpy(),
notificationSpy = ViewHelpers.createNotificationSpy();
......@@ -53,7 +53,7 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce
ViewHelpers.verifyPromptShowing(promptSpy, promptText);
ViewHelpers.confirmPrompt(promptSpy);
ViewHelpers.verifyPromptHidden(promptSpy);
if (!_.isUndefined(url) && !_.isEmpty(url)){
if (!_.isUndefined(url) && !_.isEmpty(url)) {
AjaxHelpers.expectJsonRequest(requests, 'POST', url);
expect(_.last(requests).requestHeaders['X-HTTP-Method-Override']).toBe('DELETE');
ViewHelpers.verifyNotificationShowing(notificationSpy, /Deleting/);
......@@ -62,7 +62,7 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce
}
};
var showConfirmPromptAndClickCancel = function (view, element, promptText) {
var showConfirmPromptAndClickCancel = function(view, element, promptText) {
var promptSpy = ViewHelpers.createPromptSpy();
view.$(element).click();
ViewHelpers.verifyPromptShowing(promptSpy, promptText);
......@@ -70,15 +70,15 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce
ViewHelpers.verifyPromptHidden(promptSpy);
};
var uploadFile = function (file_path, requests){
var uploadFile = function(file_path, requests) {
$(SELECTORS.uploadDialogFileInput).change();
$(SELECTORS.uploadDialogButton).click();
AjaxHelpers.respondWithJson(requests, {asset: {url: file_path}});
};
describe('Certificate editor view', function() {
var setValuesToInputs = function (view, values) {
_.each(values, function (value, selector) {
var setValuesToInputs = function(view, values) {
_.each(values, function(value, selector) {
if (SELECTORS[selector]) {
view.$(SELECTORS[selector]).val(value);
view.$(SELECTORS[selector]).trigger('change');
......@@ -86,8 +86,8 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce
});
};
var basicModalTpl = readFixtures('basic-modal.underscore'),
modalButtonTpl = readFixtures('modal-button.underscore'),
uploadDialogTpl = readFixtures('upload-dialog.underscore');
modalButtonTpl = readFixtures('modal-button.underscore'),
uploadDialogTpl = readFixtures('upload-dialog.underscore');
beforeEach(function() {
TemplateHelpers.installTemplates(['certificate-editor', 'signatory-editor'], true);
......@@ -110,8 +110,8 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce
}, this.newModelOptions);
this.collection = new CertificatesCollection([ this.model ], {
certificateUrl: '/certificates/'+ window.course.id
this.collection = new CertificatesCollection([this.model], {
certificateUrl: '/certificates/' + window.course.id
});
this.model.set('id', 0);
this.view = new CertificateEditorView({
......@@ -127,20 +127,20 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce
delete window.CMS.User;
});
describe('Basic', function () {
beforeEach(function(){
describe('Basic', function() {
beforeEach(function() {
appendSetFixtures(
$("<script>", { id: "basic-modal-tpl", type: "text/template" }).text(basicModalTpl)
$('<script>', {id: 'basic-modal-tpl', type: 'text/template'}).text(basicModalTpl)
);
appendSetFixtures(
$("<script>", { id: "modal-button-tpl", type: "text/template" }).text(modalButtonTpl)
$('<script>', {id: 'modal-button-tpl', type: 'text/template'}).text(modalButtonTpl)
);
appendSetFixtures(
$("<script>", { id: "upload-dialog-tpl", type: "text/template" }).text(uploadDialogTpl)
$('<script>', {id: 'upload-dialog-tpl', type: 'text/template'}).text(uploadDialogTpl)
);
});
afterEach(function(){
afterEach(function() {
$('.wrapper-modal-window-assetupload').remove();
});
......@@ -198,11 +198,10 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce
});
it('user can only add signatories up to limit', function() {
for(var i = 1; i < MAX_SIGNATORIES_LIMIT ; i++) {
for (var i = 1; i < MAX_SIGNATORIES_LIMIT; i++) {
this.view.$(SELECTORS.addSignatoryButton).click();
}
expect(this.view.$(SELECTORS.addSignatoryButton)).toHaveClass('disableClick');
});
it('user can add signatories if not reached the upper limit', function() {
......@@ -214,14 +213,14 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce
it('user can add signatories when signatory reached the upper limit But after deleting a signatory',
function() {
for(var i = 1; i < MAX_SIGNATORIES_LIMIT ; i++) {
for (var i = 1; i < MAX_SIGNATORIES_LIMIT; i++) {
this.view.$(SELECTORS.addSignatoryButton).click();
}
expect(this.view.$(SELECTORS.addSignatoryButton)).toHaveClass('disableClick');
// now delete anyone of the signatory, Add signatory should be enabled.
var signatory = this.model.get('signatories').at(0);
var text = 'Delete "'+ signatory.get('name') +'" from the list of signatories?';
var text = 'Delete "' + signatory.get('name') + '" from the list of signatories?';
clickDeleteItem(this, text, SELECTORS.signatoryDeleteButton + ':first');
expect(this.view.$(SELECTORS.addSignatoryButton)).not.toHaveClass('disableClick');
}
......@@ -273,8 +272,8 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce
var signatory = this.model.get('signatories').at(0);
var signatory_url = '/certificates/signatory';
signatory.url = signatory_url;
spyOn(signatory, "isNew").and.returnValue(false);
var text = 'Delete "'+ signatory.get('name') +'" from the list of signatories?';
spyOn(signatory, 'isNew').and.returnValue(false);
var text = 'Delete "' + signatory.get('name') + '" from the list of signatories?';
clickDeleteItem(this, text, SELECTORS.signatoryDeleteButton + ':first', signatory_url);
expect(this.model.get('signatories').length).toEqual(total_signatories - 1);
});
......@@ -282,13 +281,13 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce
it('can cancel deletion of signatories', function() {
this.view.$(SELECTORS.addSignatoryButton).click();
var signatory = this.model.get('signatories').at(0);
spyOn(signatory, "isNew").and.returnValue(false);
spyOn(signatory, 'isNew').and.returnValue(false);
// add one more signatory
this.view.$(SELECTORS.addSignatoryButton).click();
var total_signatories = this.model.get('signatories').length;
var signatory_url = '/certificates/signatory';
signatory.url = signatory_url;
var text = 'Delete "'+ signatory.get('name') +'" from the list of signatories?';
var text = 'Delete "' + signatory.get('name') + '" from the list of signatories?';
showConfirmPromptAndClickCancel(this.view, SELECTORS.signatoryDeleteButton + ':first', text);
expect(this.model.get('signatories').length).toEqual(total_signatories);
});
......
......@@ -19,8 +19,7 @@ function(_, $, Course, CertificatePreview, TemplateHelpers, ViewHelpers, AjaxHel
};
describe('Certificate Web Preview Spec:', function() {
var selectDropDownByText = function ( element, value ) {
var selectDropDownByText = function(element, value) {
if (value) {
element.val(value);
element.trigger('change');
......@@ -44,7 +43,7 @@ function(_, $, Course, CertificatePreview, TemplateHelpers, ViewHelpers, AjaxHel
el: $('.preview-certificate'),
course_modes: ['test1', 'test2', 'test3'],
certificate_web_view_url: '/users/1/courses/orgX/009/2016?preview=test1',
certificate_activation_handler_url: '/certificates/activation/'+ window.course.id,
certificate_activation_handler_url: '/certificates/activation/' + window.course.id,
is_active: true
});
appendSetFixtures(this.view.render().el);
......@@ -56,14 +55,14 @@ function(_, $, Course, CertificatePreview, TemplateHelpers, ViewHelpers, AjaxHel
});
describe('Certificate preview', function() {
it('course mode event should call when user choose a new mode', function () {
it('course mode event should call when user choose a new mode', function() {
spyOn(this.view, 'courseModeChanged');
this.view.delegateEvents();
selectDropDownByText(this.view.$(SELECTORS.course_modes), 'test3');
expect(this.view.courseModeChanged).toHaveBeenCalled();
});
it('course mode selection updating the link successfully', function () {
it('course mode selection updating the link successfully', function() {
selectDropDownByText(this.view.$(SELECTORS.course_modes), 'test1');
expect(this.view.$(SELECTORS.preview_certificate).attr('href')).
toEqual('/users/1/courses/orgX/009/2016?preview=test1');
......@@ -77,54 +76,52 @@ function(_, $, Course, CertificatePreview, TemplateHelpers, ViewHelpers, AjaxHel
toEqual('/users/1/courses/orgX/009/2016?preview=test3');
});
it('toggle certificate activation event works fine', function () {
it('toggle certificate activation event works fine', function() {
spyOn(this.view, 'toggleCertificateActivation');
this.view.delegateEvents();
this.view.$(SELECTORS.activate_certificate).click();
expect(this.view.toggleCertificateActivation).toHaveBeenCalled();
});
it('toggle certificate activation button should not be present if user is not global staff', function () {
it('toggle certificate activation button should not be present if user is not global staff', function() {
window.CMS.User = {isGlobalStaff: false};
appendSetFixtures(this.view.render().el);
expect(this.view.$(SELECTORS.activate_certificate)).not.toExist();
});
it('certificate deactivation works fine', function () {
it('certificate deactivation works fine', function() {
var requests = AjaxHelpers.requests(this),
notificationSpy = ViewHelpers.createNotificationSpy();
this.view.$(SELECTORS.activate_certificate).click();
AjaxHelpers.expectJsonRequest(requests, 'POST', '/certificates/activation/'+ window.course.id, {
AjaxHelpers.expectJsonRequest(requests, 'POST', '/certificates/activation/' + window.course.id, {
is_active: false
});
ViewHelpers.verifyNotificationShowing(notificationSpy, /Deactivating/);
});
it('certificate activation works fine', function () {
it('certificate activation works fine', function() {
var requests = AjaxHelpers.requests(this),
notificationSpy = ViewHelpers.createNotificationSpy();
this.view.is_active = false;
this.view.$(SELECTORS.activate_certificate).click();
AjaxHelpers.expectJsonRequest(requests, 'POST', '/certificates/activation/'+ window.course.id, {
AjaxHelpers.expectJsonRequest(requests, 'POST', '/certificates/activation/' + window.course.id, {
is_active: true
});
ViewHelpers.verifyNotificationShowing(notificationSpy, /Activating/);
});
it('certificate should be deactivate when method "remove" called', function () {
it('certificate should be deactivate when method "remove" called', function() {
this.view.remove();
expect(this.view.is_active).toBe(false);
});
it('certificate web preview should be removed when method "remove" called', function () {
it('certificate web preview should be removed when method "remove" called', function() {
this.view.remove();
expect(this.view.el.innerHTML).toBe('');
});
it('method "show" should call the render function', function () {
spyOn(this.view, "render");
it('method "show" should call the render function', function() {
spyOn(this.view, 'render');
this.view.show();
expect(this.view.render).toHaveBeenCalled();
});
......
......@@ -16,7 +16,7 @@ define([
'js/certificates/spec/custom_matchers'
],
function(_, Course, CertificatesCollection, CertificateModel, CertificateDetailsView, CertificateEditorView,
CertificateItemView, CertificatesListView, CertificatePreview, Notification, AjaxHelpers, TemplateHelpers,
CertificateItemView, CertificatesListView, CertificatePreview, Notification, AjaxHelpers, TemplateHelpers,
CustomMatchers) {
'use strict';
......@@ -54,7 +54,7 @@ function(_, Course, CertificatesCollection, CertificateModel, CertificateDetails
}, {add: true});
this.collection = new CertificatesCollection([], {
certificateUrl: '/certificates/'+ window.course.id
certificateUrl: '/certificates/' + window.course.id
});
this.model.set('id', 0);
this.view = new CertificatesListView({
......@@ -70,7 +70,7 @@ function(_, Course, CertificatesCollection, CertificateModel, CertificateDetails
delete window.CMS.User;
});
describe('empty template', function () {
describe('empty template', function() {
it('should be rendered if no certificates', function() {
expect(this.view.$(SELECTORS.noContent)).toExist();
expect(this.view.$(SELECTORS.noContent)).toContainText(emptyMessage);
......@@ -99,7 +99,6 @@ function(_, Course, CertificatesCollection, CertificateModel, CertificateDetails
this.collection.add(this.model);
expect(this.view.$(SELECTORS.itemEditView)).toExist();
});
});
});
});
......@@ -21,7 +21,7 @@ function($, _, str, gettext, BaseView, SignatoryModel, SignatoryDetailsView, Vie
'click .edit': 'editCertificate'
},
className: function () {
className: function() {
// Determine the CSS class names for this model instance
return [
'collection',
......@@ -40,7 +40,7 @@ function($, _, str, gettext, BaseView, SignatoryModel, SignatoryDetailsView, Vie
// Flip the model into 'editing' mode
if (event && event.preventDefault) { event.preventDefault(); }
var self = this;
if (this.model.get("is_active") === true){
if (this.model.get('is_active') === true) {
ViewUtils.confirmThenRunOperation(
gettext('Edit this certificate?'),
gettext('This certificate has already been activated and is live. Are you sure you want to continue editing?'),
......@@ -50,7 +50,7 @@ function($, _, str, gettext, BaseView, SignatoryModel, SignatoryDetailsView, Vie
}
);
}
else{
else {
this.model.set('editing', true);
}
},
......@@ -63,15 +63,15 @@ function($, _, str, gettext, BaseView, SignatoryModel, SignatoryDetailsView, Vie
showDetails: this.showDetails || showDetails || false
});
this.$el.html(_.template(certificateDetailsTemplate)(attrs));
if(this.showDetails || showDetails) {
if (this.showDetails || showDetails) {
var self = this;
this.model.get("signatories").each(function (modelSignatory) {
this.model.get('signatories').each(function(modelSignatory) {
var signatory_detail_view = new SignatoryDetailsView({model: modelSignatory});
self.$('div.signatory-details-list').append($(signatory_detail_view.render().$el));
});
}
if(this.model.collection.length > 0 && window.certWebPreview) {
if (this.model.collection.length > 0 && window.certWebPreview) {
window.certWebPreview.show();
}
$.smoothScroll({
......
......@@ -30,7 +30,7 @@ function($, _, Backbone, gettext,
'click .action-add-signatory': 'addSignatory'
},
className: function () {
className: function() {
// Determine the CSS class names for this model instance
var index = this.model.collection.indexOf(this.model);
......@@ -44,12 +44,12 @@ function($, _, Backbone, gettext,
initialize: function(options) {
// Set up the initial state of the attributes set for this model instance
_.bindAll(this, "onSignatoryRemoved", "clearErrorMessage");
_.bindAll(this, 'onSignatoryRemoved', 'clearErrorMessage');
this.max_signatories_limit = options.max_signatories_limit || MAX_SIGNATORIES_LIMIT;
this.template = _.template(certificateEditorTemplate);
this.eventAgg = _.extend({}, Backbone.Events);
this.eventAgg.bind("onSignatoryRemoved", this.onSignatoryRemoved);
this.eventAgg.bind("onSignatoryUpdated", this.clearErrorMessage);
this.eventAgg.bind('onSignatoryRemoved', this.onSignatoryRemoved);
this.eventAgg.bind('onSignatoryUpdated', this.clearErrorMessage);
ListItemEditorView.prototype.initialize.call(this);
},
......@@ -69,7 +69,7 @@ function($, _, Backbone, gettext,
ListItemEditorView.prototype.render.call(this);
var self = this;
// Ensure we have at least one signatory associated with the certificate.
this.model.get("signatories").each(function( modelSignatory) {
this.model.get('signatories').each(function(modelSignatory) {
var signatory_view = new SignatoryEditorView({
model: modelSignatory,
isEditingAllCollections: true,
......@@ -89,8 +89,8 @@ function($, _, Backbone, gettext,
disableAddSignatoryButton: function() {
// Disable the 'Add Signatory' link if the constraint has been met.
if(this.$(".signatory-edit-list > div.signatory-edit").length >= this.max_signatories_limit) {
this.$(".action-add-signatory").addClass("disableClick");
if (this.$('.signatory-edit-list > div.signatory-edit').length >= this.max_signatories_limit) {
this.$('.action-add-signatory').addClass('disableClick');
}
},
......@@ -118,7 +118,7 @@ function($, _, Backbone, gettext,
if (event && event.preventDefault) { event.preventDefault(); }
this.model.set(
'name', this.$('.collection-name-input').val(),
{ silent: true }
{silent: true}
);
},
......@@ -128,7 +128,7 @@ function($, _, Backbone, gettext,
this.model.set(
'description',
this.$('.certificate-description-input').val(),
{ silent: true }
{silent: true}
);
},
......@@ -138,7 +138,7 @@ function($, _, Backbone, gettext,
this.model.set(
'course_title',
this.$('.certificate-course-title-input').val(),
{ silent: true }
{silent: true}
);
},
......
......@@ -7,7 +7,7 @@ define([
'js/certificates/views/certificate_details',
'js/certificates/views/certificate_editor'
],
function (gettext, ListItemView, CertificateDetailsView, CertificateEditorView) {
function(gettext, ListItemView, CertificateDetailsView, CertificateEditorView) {
'use strict';
var CertificateItemView = ListItemView.extend({
events: {
......@@ -20,7 +20,7 @@ function (gettext, ListItemView, CertificateDetailsView, CertificateEditorView)
// Translators: This field pertains to the custom label for a certificate.
itemDisplayName: gettext('certificate'),
attributes: function () {
attributes: function() {
// Retrieves the defined attribute set
return {
'id': this.model.get('id'),
......
......@@ -8,25 +8,25 @@ define([
'js/views/baseview',
'common/js/components/utils/view_utils',
'common/js/components/views/feedback_notification',
"text!templates/certificate-web-preview.underscore"
'text!templates/certificate-web-preview.underscore'
],
function(_, gettext, BaseView, ViewUtils, NotificationView, certificateWebPreviewTemplate) {
'use strict';
var CertificateWebPreview = BaseView.extend({
el: $(".preview-certificate"),
el: $('.preview-certificate'),
events: {
"change #course-modes": "courseModeChanged",
"click .activate-cert": "toggleCertificateActivation"
'change #course-modes': 'courseModeChanged',
'click .activate-cert': 'toggleCertificateActivation'
},
initialize: function (options) {
initialize: function(options) {
this.course_modes = options.course_modes;
this.certificate_web_view_url = options.certificate_web_view_url;
this.certificate_activation_handler_url = options.certificate_activation_handler_url;
this.is_active = options.is_active;
},
render: function () {
render: function() {
this.$el.html(_.template(certificateWebPreviewTemplate)({
course_modes: this.course_modes,
certificate_web_view_url: this.certificate_web_view_url,
......@@ -36,9 +36,9 @@ function(_, gettext, BaseView, ViewUtils, NotificationView, certificateWebPrevie
},
toggleCertificateActivation: function() {
var msg = "Activating";
if(this.is_active) {
msg = "Deactivating";
var msg = 'Activating';
if (this.is_active) {
msg = 'Deactivating';
}
var notification = new NotificationView.Mini({
......@@ -47,24 +47,24 @@ function(_, gettext, BaseView, ViewUtils, NotificationView, certificateWebPrevie
$.ajax({
url: this.certificate_activation_handler_url,
type: "POST",
dataType: "json",
contentType: "application/json",
type: 'POST',
dataType: 'json',
contentType: 'application/json',
data: JSON.stringify({
is_active: !this.is_active
}),
beforeSend: function() {
notification.show();
},
success: function(){
success: function() {
notification.hide();
location.reload();
}
});
},
courseModeChanged: function (event) {
$('.preview-certificate-link').attr('href', function(index, value){
courseModeChanged: function(event) {
$('.preview-certificate-link').attr('href', function(index, value) {
return value.replace(/preview=([^&]+)/, function() {
return 'preview=' + event.target.options[event.target.selectedIndex].text;
});
......
......@@ -5,7 +5,7 @@ define([
'js/views/list',
'js/certificates/views/certificate_item'
],
function (gettext, ListView, CertificateItemView) {
function(gettext, ListView, CertificateItemView) {
'use strict';
var CertificatesListView = ListView.extend({
tagName: 'div',
......
......@@ -7,7 +7,7 @@ define([
'js/views/pages/base_page',
'js/certificates/views/certificates_list'
],
function ($, _, gettext, BasePage, CertificatesListView) {
function($, _, gettext, BasePage, CertificatesListView) {
'use strict';
var CertificatesPage = BasePage.extend({
......
......@@ -13,7 +13,7 @@ define([
'text!templates/signatory-details.underscore',
'text!templates/signatory-actions.underscore'
],
function ($, _, str, Backbone, gettext, TemplateUtils, ViewUtils, BaseView, SignatoryEditorView,
function($, _, str, Backbone, gettext, TemplateUtils, ViewUtils, BaseView, SignatoryEditorView,
signatoryDetailsTemplate, signatoryActionsTemplate) {
'use strict';
var SignatoryDetailsView = BaseView.extend({
......@@ -25,7 +25,7 @@ function ($, _, str, Backbone, gettext, TemplateUtils, ViewUtils, BaseView, Sign
},
className: function () {
className: function() {
// Determine the CSS class names for this model instance
var index = this.model.collection.indexOf(this.model);
return [
......@@ -62,13 +62,13 @@ function ($, _, str, Backbone, gettext, TemplateUtils, ViewUtils, BaseView, Sign
// Persist the data for this model
if (event && event.preventDefault) { event.preventDefault(); }
var certificate = this.model.get('certificate');
if (!certificate.isValid()){
if (!certificate.isValid()) {
return;
}
var self = this;
ViewUtils.runOperationShowingMessage(
gettext('Saving'),
function () {
function() {
var dfd = $.Deferred();
var actionableModel = certificate;
actionableModel.save({}, {
......
......@@ -13,7 +13,7 @@ define([
'js/views/uploads',
'text!templates/signatory-editor.underscore'
],
function ($, _, Backbone, gettext,
function($, _, Backbone, gettext,
TemplateUtils, ViewUtils, PromptView, NotificationView, FileUploadModel, FileUploadDialog,
signatoryEditorTemplate) {
'use strict';
......@@ -28,7 +28,7 @@ function ($, _, Backbone, gettext,
'click .action-upload-signature': 'uploadSignatureImage'
},
className: function () {
className: function() {
// Determine the CSS class names for this model instance
var index = this.getModelIndex(this.model);
return [
......@@ -39,7 +39,7 @@ function ($, _, Backbone, gettext,
initialize: function(options) {
// Set up the initial state of the attributes set for this model instance
_.bindAll(this, 'render');
_.bindAll(this, 'render');
this.model.bind('change', this.render);
this.eventAgg = options.eventAgg;
this.isEditingAllCollections = options.isEditingAllCollections;
......@@ -58,8 +58,8 @@ function ($, _, Backbone, gettext,
getTotalSignatoriesOnServer: function() {
// Retrieve the count of signatories stored server-side
var count = 0;
this.model.collection.each(function( modelSignatory) {
if(!modelSignatory.isNew()) {
this.model.collection.each(function(modelSignatory) {
if (!modelSignatory.isNew()) {
count ++;
}
});
......@@ -87,10 +87,10 @@ function ($, _, Backbone, gettext,
this.model.set(
'name',
this.$('.signatory-name-input').val(),
{ silent: true }
{silent: true}
);
this.toggleValidationErrorMessage('name');
this.eventAgg.trigger("onSignatoryUpdated", this.model);
this.eventAgg.trigger('onSignatoryUpdated', this.model);
},
setSignatoryTitle: function(event) {
......@@ -99,10 +99,10 @@ function ($, _, Backbone, gettext,
this.model.set(
'title',
this.$('.signatory-title-input').val(),
{ silent:true }
{silent: true}
);
this.toggleValidationErrorMessage('title');
this.eventAgg.trigger("onSignatoryUpdated", this.model);
this.eventAgg.trigger('onSignatoryUpdated', this.model);
},
setSignatoryOrganization: function(event) {
......@@ -111,9 +111,9 @@ function ($, _, Backbone, gettext,
this.model.set(
'organization',
this.$('.signatory-organization-input').val(),
{ silent: true }
{silent: true}
);
this.eventAgg.trigger("onSignatoryUpdated", this.model);
this.eventAgg.trigger('onSignatoryUpdated', this.model);
},
setSignatorySignatureImagePath: function(event) {
......@@ -121,7 +121,7 @@ function ($, _, Backbone, gettext,
this.model.set(
'signature_image_path',
this.$('.signatory-signature-input').val(),
{ silent: true }
{silent: true}
);
},
......@@ -137,21 +137,21 @@ function ($, _, Backbone, gettext,
actions: {
primary: {
text: gettext('Delete'),
click: function () {
click: function() {
var deleting = new NotificationView.Mini({
title: gettext('Deleting')
});
if (model.isNew()){
if (model.isNew()) {
model.collection.remove(model);
self.eventAgg.trigger("onSignatoryRemoved", model);
self.eventAgg.trigger('onSignatoryRemoved', model);
}
else {
deleting.show();
model.destroy({
wait: true,
success: function (model) {
success: function(model) {
deleting.hide();
self.eventAgg.trigger("onSignatoryRemoved", model);
self.eventAgg.trigger('onSignatoryRemoved', model);
}
});
}
......@@ -172,8 +172,8 @@ function ($, _, Backbone, gettext,
uploadSignatureImage: function(event) {
event.preventDefault();
var upload = new FileUploadModel({
title: gettext("Upload signature image."),
message: gettext("Image must be in PNG format."),
title: gettext('Upload signature image.'),
message: gettext('Image must be in PNG format.'),
mimeTypes: ['image/png']
});
var self = this;
......@@ -192,20 +192,19 @@ function ($, _, Backbone, gettext,
* @param string modelAttribute - the attribute of the signatory model e.g. name, title.
*/
toggleValidationErrorMessage: function(modelAttribute) {
var selector = "div.add-signatory-" + modelAttribute;
var selector = 'div.add-signatory-' + modelAttribute;
if (!this.model.isValid() && _.has(this.model.validationError, modelAttribute)) {
// Show the error message if it is not exist before.
if( !$(selector).hasClass('error')) {
if (!$(selector).hasClass('error')) {
var errorMessage = this.model.validationError[modelAttribute];
$(selector).addClass("error");
$(selector).append("<span class='message-error'>" + errorMessage + "</span>");
$(selector).addClass('error');
$(selector).append("<span class='message-error'>" + errorMessage + '</span>');
}
}
else {
// Remove the error message.
$(selector).removeClass("error");
$(selector + ">span.message-error").remove();
$(selector).removeClass('error');
$(selector + '>span.message-error').remove();
}
}
......
define([
"underscore",
"edx-ui-toolkit/js/pagination/paging-collection",
"js/models/asset"
'underscore',
'edx-ui-toolkit/js/pagination/paging-collection',
'js/models/asset'
], function(_, PagingCollection, AssetModel) {
'use strict';
var AssetCollection = PagingCollection.extend({
assetType: '',
model : AssetModel,
model: AssetModel,
state: {
firstPage: 0,
......
define(["backbone", "js/models/chapter"], function(Backbone, ChapterModel) {
define(['backbone', 'js/models/chapter'], function(Backbone, ChapterModel) {
var ChapterCollection = Backbone.Collection.extend({
model: ChapterModel,
comparator: "order",
comparator: 'order',
nextOrder: function() {
if(!this.length) return 1;
if (!this.length) return 1;
return this.last().get('order') + 1;
},
isEmpty: function() {
......
define(["backbone", "js/models/component_template"], function(Backbone, ComponentTemplate) {
define(['backbone', 'js/models/component_template'], function(Backbone, ComponentTemplate) {
return Backbone.Collection.extend({
model : ComponentTemplate
model: ComponentTemplate
});
});
define(["backbone", "js/models/settings/course_grader"], function(Backbone, CourseGrader) {
define(['backbone', 'js/models/settings/course_grader'], function(Backbone, CourseGrader) {
var CourseGraderCollection = Backbone.Collection.extend({
model: CourseGrader,
sumWeights: function() {
return this.reduce(function(subtotal, grader) { return subtotal + grader.get('weight'); }, 0);
}
});
var CourseGraderCollection = Backbone.Collection.extend({
model : CourseGrader,
sumWeights : function() {
return this.reduce(function(subtotal, grader) { return subtotal + grader.get('weight'); }, 0);
}
});
return CourseGraderCollection;
return CourseGraderCollection;
}); // end define()
define(["backbone", "js/models/course_update"], function(Backbone, CourseUpdateModel) {
define(['backbone', 'js/models/course_update'], function(Backbone, CourseUpdateModel) {
/*
The intitializer of this collection must set id to the update's location.url and courseLocation to the course's location. Must pass the
collection of updates as [{ date : "month day", content : "html"}]
......@@ -6,7 +6,7 @@ define(["backbone", "js/models/course_update"], function(Backbone, CourseUpdateM
var CourseUpdateCollection = Backbone.Collection.extend({
// instantiator must set url
model : CourseUpdateModel
model: CourseUpdateModel
});
return CourseUpdateCollection;
});
define([
'underscore', 'underscore.string', 'backbone', 'gettext', 'js/models/group'
],
function (_, str, Backbone, gettext, GroupModel) {
function(_, str, Backbone, gettext, GroupModel) {
'use strict';
var GroupCollection = Backbone.Collection.extend({
model: GroupModel,
......@@ -11,7 +11,7 @@ function (_, str, Backbone, gettext, GroupModel) {
* @return {Number}
*/
nextOrder: function() {
if(!this.length) {
if (!this.length) {
return 0;
}
......@@ -33,7 +33,7 @@ function (_, str, Backbone, gettext, GroupModel) {
* @examples
* Group A, Group B, Group AA, Group ZZZ etc.
*/
getNextDefaultGroupName: function () {
getNextDefaultGroupName: function() {
var index = this.nextOrder(),
usedNames = _.pluck(this.toJSON(), 'name'),
name = '';
......@@ -53,7 +53,7 @@ function (_, str, Backbone, gettext, GroupModel) {
* @examples
* A, B, AA in Group A, Group B, ..., Group AA, etc.
*/
getGroupId: (function () {
getGroupId: (function() {
/*
Translators: Dictionary used for creation ids that are used in
default group names. For example: A, B, AA in Group A,
......
define(["backbone", "js/models/metadata"], function(Backbone, MetadataModel) {
define(['backbone', 'js/models/metadata'], function(Backbone, MetadataModel) {
var MetadataCollection = Backbone.Collection.extend({
model : MetadataModel,
comparator: "display_name"
model: MetadataModel,
comparator: 'display_name'
});
return MetadataCollection;
});
define(["backbone", "js/models/textbook"],
define(['backbone', 'js/models/textbook'],
function(Backbone, TextbookModel) {
var TextbookCollection = Backbone.Collection.extend({
model: TextbookModel,
url: function() { return CMS.URL.TEXTBOOKS; }
});
return TextbookCollection;
});
var TextbookCollection = Backbone.Collection.extend({
model: TextbookModel,
url: function() { return CMS.URL.TEXTBOOKS; }
});
return TextbookCollection;
});
......@@ -2,17 +2,17 @@ define([
'jquery', 'js/collections/asset', 'js/views/assets', 'jquery.fileupload'
], function($, AssetCollection, AssetsView) {
'use strict';
return function (config) {
return function(config) {
var assets = new AssetCollection(),
assetsView;
assets.url = config.assetCallbackUrl;
assetsView = new AssetsView({
collection: assets,
el: $('.wrapper-assets'),
uploadChunkSizeInMBs: config.uploadChunkSizeInMBs,
maxFileSizeInMBs: config.maxFileSizeInMBs,
maxFileSizeRedirectUrl: config.maxFileSizeRedirectUrl
collection: assets,
el: $('.wrapper-assets'),
uploadChunkSizeInMBs: config.uploadChunkSizeInMBs,
maxFileSizeInMBs: config.maxFileSizeInMBs,
maxFileSizeRedirectUrl: config.maxFileSizeRedirectUrl
});
assetsView.render();
};
......
......@@ -5,7 +5,7 @@ define([
],
function($, _, XBlockContainerInfo, ContainerPage, ComponentTemplates, xmoduleLoader) {
'use strict';
return function (componentTemplates, XBlockInfoJson, action, options) {
return function(componentTemplates, XBlockInfoJson, action, options) {
var main_options = {
el: $('#content'),
model: new XBlockContainerInfo(XBlockInfoJson, {parse: true}),
......@@ -13,7 +13,7 @@ function($, _, XBlockContainerInfo, ContainerPage, ComponentTemplates, xmoduleLo
templates: new ComponentTemplates(componentTemplates, {parse: true})
};
xmoduleLoader.done(function () {
xmoduleLoader.done(function() {
var view = new ContainerPage(_.extend(main_options, options));
view.render();
});
......
define(['jquery', 'jquery.form', 'js/views/course_rerun'], function ($) {
define(['jquery', 'jquery.form', 'js/views/course_rerun'], function($) {
'use strict';
return function () {};
return function() {};
});
......@@ -3,7 +3,7 @@ define([
'js/models/course_info', 'js/views/course_info_edit'
], function($, CourseUpdateCollection, ModuleInfoModel, CourseInfoModel, CourseInfoEditView) {
'use strict';
return function (updatesUrl, handoutsLocator, baseAssetUrl, push_notification_enabled) {
return function(updatesUrl, handoutsLocator, baseAssetUrl, push_notification_enabled) {
var course_updates = new CourseUpdateCollection(),
course_handouts, editor;
......@@ -14,10 +14,10 @@ define([
});
editor = new CourseInfoEditView({
el: $('.main-wrapper'),
model : new CourseInfoModel({
updates : course_updates,
base_asset_url : baseAssetUrl,
handouts : course_handouts
model: new CourseInfoModel({
updates: course_updates,
base_asset_url: baseAssetUrl,
handouts: course_handouts
}),
push_notification_enabled: push_notification_enabled
});
......
define([
'js/models/explicit_url', 'js/views/tabs', 'xmodule', 'cms/js/main', 'xblock/cms.runtime.v1'
], function (TabsModel, TabsEditView, xmoduleLoader) {
], function(TabsModel, TabsEditView, xmoduleLoader) {
'use strict';
return function (courseLocation, explicitUrl) {
xmoduleLoader.done(function () {
return function(courseLocation, explicitUrl) {
xmoduleLoader.done(function() {
var model = new TabsModel({
id: courseLocation,
explicit_url: explicitUrl
......
define(['gettext', 'common/js/components/views/feedback_prompt'], function(gettext, PromptView) {
'use strict';
return function (hasUnit, editUnitUrl, courselikeHomeUrl, library, errMsg) {
return function(hasUnit, editUnitUrl, courselikeHomeUrl, library, errMsg) {
var dialog;
if(hasUnit) {
if (hasUnit) {
dialog = new PromptView({
title: gettext('There has been an error while exporting.'),
message: gettext('There has been a failure to export to XML at least one component. It is recommended that you go to the edit page and repair the error before attempting another export. Please check that all components on the page are valid and do not display any error messages.'),
......@@ -28,10 +28,10 @@ define(['gettext', 'common/js/components/views/feedback_prompt'], function(gette
var action;
if (library) {
msg += gettext('Your library could not be exported to XML. There is not enough information to identify the failed component. Inspect your library to identify any problematic components and try again.');
action = gettext('Take me to the main library page')
action = gettext('Take me to the main library page');
} else {
msg += gettext('Your course could not be exported to XML. There is not enough information to identify the failed component. Inspect your course to identify any problematic components and try again.');
action = gettext('Take me to the main course page')
action = gettext('Take me to the main course page');
}
msg += '</p><p>' + gettext('The raw error message is:') + '</p>' + errMsg;
dialog = new PromptView({
......@@ -49,7 +49,7 @@ define(['gettext', 'common/js/components/views/feedback_prompt'], function(gette
secondary: {
text: gettext('Cancel'),
click: function(view) {
view.hide();
view.hide();
}
}
}
......
......@@ -2,7 +2,7 @@ define([
'js/collections/group_configuration', 'js/models/group_configuration', 'js/views/pages/group_configurations'
], function(GroupConfigurationCollection, GroupConfigurationModel, GroupConfigurationsPage) {
'use strict';
return function (experimentsEnabled, experimentGroupConfigurationsJson, contentGroupConfigurationJson,
return function(experimentsEnabled, experimentGroupConfigurationsJson, contentGroupConfigurationJson,
groupConfigurationUrl, courseOutlineUrl) {
var experimentGroupConfigurations = new GroupConfigurationCollection(
experimentGroupConfigurationsJson, {parse: true}
......
define([
'domReady', 'js/views/import', 'jquery', 'gettext', 'jquery.fileupload', 'jquery.cookie'
], function(domReady, Import, $, gettext) {
'use strict';
return function (feedbackUrl, library) {
return function(feedbackUrl, library) {
var dbError;
if (library) {
......@@ -27,14 +26,14 @@ define([
previousImport = Import.storedImport(),
file;
var onComplete = function () {
var onComplete = function() {
bar.hide();
chooseBtn
.find('.copy').html(gettext("Choose new file")).end()
.find('.copy').html(gettext('Choose new file')).end()
.show();
}
};
$(window).on('beforeunload', function (event) { unloading = true; });
$(window).on('beforeunload', function(event) { unloading = true; });
// Display the status of last file upload on page load
if (previousImport) {
......@@ -70,11 +69,11 @@ define([
).then(onComplete);
submitBtn.hide();
data.submit().complete(function (result, textStatus, xhr) {
data.submit().complete(function(result, textStatus, xhr) {
if (xhr.status !== 200) {
var serverMsg, errMsg, stage;
try{
try {
serverMsg = $.parseJSON(result.responseText) || {};
} catch (e) {
return;
......@@ -104,7 +103,7 @@ define([
}
},
progressall: function(e, data){
progressall: function(e, data) {
var percentInt = data.loaded / data.total * 100,
percentVal = parseInt(percentInt, 10) + '%',
doneAt;
......@@ -121,7 +120,7 @@ define([
// Start feedback with delay so that current stage of
// import properly updates in session
setTimeout(function () { Import.pollStatus(); }, 3000);
setTimeout(function() { Import.pollStatus(); }, 3000);
} else {
bar.show();
fill.width(percentVal).html(percentVal);
......@@ -132,7 +131,7 @@ define([
});
var showImportSubmit = function (e) {
var showImportSubmit = function(e) {
var filepath = $(this).val();
if (filepath.substr(filepath.length - 6, 6) === 'tar.gz') {
......@@ -150,10 +149,10 @@ define([
}
};
domReady(function () {
domReady(function() {
// import form setup
$('.view-import .file-input').bind('change', showImportSubmit);
$('.view-import .choose-file-button, .view-import .choose-file-button-inline').bind('click', function (e) {
$('.view-import .choose-file-button, .view-import .choose-file-button-inline').bind('click', function(e) {
e.preventDefault();
$('.view-import .file-input').click();
});
......
define(['jquery.form', 'js/index'], function() {
'use strict';
return function () {
return function() {
// showing/hiding creation rights UI
$('.show-creationrights').click(function(e) {
e.preventDefault();
......@@ -11,11 +11,11 @@ define(['jquery.form', 'js/index'], function() {
.toggleClass('current');
});
var reloadPage = function () {
var reloadPage = function() {
location.reload();
};
var showError = function () {
var showError = function() {
$('#request-coursecreator-submit')
.toggleClass('has-error')
.find('.label')
......@@ -30,7 +30,7 @@ define(['jquery.form', 'js/index'], function() {
success: reloadPage
});
$('#request-coursecreator-submit').click(function(event){
$('#request-coursecreator-submit').click(function(event) {
$(this)
.toggleClass('is-disabled is-submitting')
.attr('aria-disabled', $(this).hasClass('is-disabled'))
......
......@@ -5,7 +5,7 @@ define([
],
function($, _, XBlockInfo, PagedContainerPage, LibraryContainerView, ComponentTemplates, xmoduleLoader) {
'use strict';
return function (componentTemplates, XBlockInfoJson, options) {
return function(componentTemplates, XBlockInfoJson, options) {
var main_options = {
el: $('#content'),
model: new XBlockInfo(XBlockInfoJson, {parse: true}),
......@@ -15,7 +15,7 @@ function($, _, XBlockInfo, PagedContainerPage, LibraryContainerView, ComponentTe
canEdit: true
};
xmoduleLoader.done(function () {
xmoduleLoader.done(function() {
var view = new PagedContainerPage(_.extend(main_options, options));
view.render();
});
......
define(['jquery.cookie', 'utility', 'common/js/components/utils/view_utils'], function(cookie, utility, ViewUtils) {
'use strict';
return function (homepageURL) {
return function(homepageURL) {
function postJSON(url, data, callback) {
$.ajax({
type:'POST',
type: 'POST',
url: url,
dataType: 'json',
data: data,
success: callback,
success: callback
});
}
// Clear the login error message when credentials are edited
$('input#email').on('input',function() {
$('input#email').on('input', function() {
$('#login_error').removeClass('is-shown');
});
$('input#password').on('input',function() {
$('input#password').on('input', function() {
$('#login_error').removeClass('is-shown');
});
......@@ -29,14 +29,14 @@ define(['jquery.cookie', 'utility', 'common/js/components/utils/view_utils'], fu
var submit_data = $('#login_form').serialize();
postJSON('/login_post', submit_data, function(json) {
if(json.success) {
if (json.success) {
var next = /next=([^&]*)/g.exec(decodeURIComponent(window.location.search));
if (next && next.length > 1 && !isExternal(next[1])) {
ViewUtils.redirect(next[1]);
} else {
ViewUtils.redirect(homepageURL);
}
} else if($('#login_error').length === 0) {
} else if ($('#login_error').length === 0) {
$('#login_form').prepend(
'<div id="login_error" class="message message-status error">' +
json.value +
......
......@@ -4,7 +4,7 @@
define(['underscore', 'gettext', 'js/views/manage_users_and_roles'],
function(_, gettext, ManageUsersAndRoles) {
'use strict';
return function (containerName, users, tplUserURL, current_user_id, allow_actions) {
return function(containerName, users, tplUserURL, current_user_id, allow_actions) {
function updateMessages(messages) {
var local_messages = _.extend({}, messages);
local_messages.alreadyMember.title = gettext('Already a course team member');
......@@ -16,10 +16,10 @@ function(_, gettext, ManageUsersAndRoles) {
// Roles order are important: first role is considered initial role (the role added to user when (s)he's added
// Last role is considered an admin role (unrestricted access + ability to manage other users' permissions)
// Changing roles is performed in promote-demote fashion, so moves only to adjacent roles is allowed
var roles = [{key:'staff', name:gettext('Staff')}, {key:'instructor', 'name': gettext("Admin")}];
var roles = [{key: 'staff', name: gettext('Staff')}, {key: 'instructor', 'name': gettext('Admin')}];
var options = {
el: $("#content"),
el: $('#content'),
containerName: containerName,
tplUserURL: tplUserURL,
roles: roles,
......
......@@ -4,7 +4,7 @@
define(['underscore', 'gettext', 'js/views/manage_users_and_roles'],
function(_, gettext, ManageUsersAndRoles) {
'use strict';
return function (containerName, users, tplUserURL, current_user_id, allow_actions) {
return function(containerName, users, tplUserURL, current_user_id, allow_actions) {
function updateMessages(messages) {
var local_messages = _.extend({}, messages);
local_messages.alreadyMember.title = gettext('Already a library team member');
......@@ -17,13 +17,13 @@ function(_, gettext, ManageUsersAndRoles) {
// Last role is considered an admin role (unrestricted access + ability to manage other users' permissions)
// Changing roles is performed in promote-demote fashion, so moves only to adjacent roles is allowed
var roles = [
{key:'library_user', name:gettext('Library User')},
{key:'staff', name:gettext('Staff')},
{key:'instructor', 'name': gettext("Admin")}
{key: 'library_user', name: gettext('Library User')},
{key: 'staff', name: gettext('Staff')},
{key: 'instructor', 'name': gettext('Admin')}
];
var options = {
el: $("#content"),
el: $('#content'),
containerName: containerName,
tplUserURL: tplUserURL,
roles: roles,
......
......@@ -2,7 +2,7 @@ define([
'js/views/pages/course_outline', 'js/models/xblock_outline_info'
], function(CourseOutlinePage, XBlockOutlineInfo) {
'use strict';
return function (XBlockOutlineInfoJson, initialStateJson) {
return function(XBlockOutlineInfoJson, initialStateJson) {
var courseXBlock = new XBlockOutlineInfo(XBlockOutlineInfoJson, {parse: true}),
view = new CourseOutlinePage({
el: $('#content'),
......
define(['jquery', 'jquery.cookie'], function($) {
'use strict';
return function () {
return function() {
$('form :input')
.focus(function() {
$('label[for="' + this.id + '"]').addClass('is-focused');
......@@ -21,11 +21,11 @@ define(['jquery', 'jquery.cookie'], function($) {
notifyOnError: false,
data: submit_data,
success: function(json) {
location.href = '/course/';
location.href = '/course/';
},
error: function(jqXHR, textStatus, errorThrown) {
var json = $.parseJSON(jqXHR.responseText);
$('#register_error').html(json.value).stop().addClass('is-shown');
var json = $.parseJSON(jqXHR.responseText);
$('#register_error').html(json.value).stop().addClass('is-shown');
}
});
});
......
......@@ -2,7 +2,7 @@ define([
'jquery', 'js/models/settings/course_details', 'js/views/settings/main'
], function($, CourseDetailsModel, MainView) {
'use strict';
return function (detailsUrl, showMinGradeWarning) {
return function(detailsUrl, showMinGradeWarning) {
var model;
// highlighting labels when fields are focused in
$('form :input')
......
......@@ -2,7 +2,7 @@ define([
'jquery', 'gettext', 'js/models/settings/advanced', 'js/views/settings/advanced'
], function($, gettext, AdvancedSettingsModel, AdvancedSettingsView) {
'use strict';
return function (advancedDict, advancedSettingsUrl) {
return function(advancedDict, advancedSettingsUrl) {
var advancedModel, editor;
$('form :input')
......
......@@ -2,7 +2,7 @@ define([
'jquery', 'js/views/settings/grading', 'js/models/settings/course_grading_policy'
], function($, GradingView, CourseGradingPolicyModel) {
'use strict';
return function (courseDetails, gradingUrl) {
return function(courseDetails, gradingUrl) {
var model, editor;
$('form :input')
......@@ -13,11 +13,11 @@ define([
$('label').removeClass('is-focused');
});
model = new CourseGradingPolicyModel(courseDetails,{parse:true});
model = new CourseGradingPolicyModel(courseDetails, {parse: true});
model.urlRoot = gradingUrl;
editor = new GradingView({
el: $('.settings-grading'),
model : model
model: model
});
editor.render();
};
......
......@@ -2,7 +2,7 @@ define([
'gettext', 'js/models/section', 'js/collections/textbook', 'js/views/list_textbooks'
], function(gettext, Section, TextbookCollection, ListTextbooksView) {
'use strict';
return function (textbooksJson) {
return function(textbooksJson) {
var textbooks = new TextbookCollection(textbooksJson, {parse: true}),
tbView = new ListTextbooksView({collection: textbooks});
......@@ -12,7 +12,7 @@ define([
});
$(window).on('beforeunload', function() {
var dirty = textbooks.find(function(textbook) { return textbook.isDirty(); });
if(dirty) {
if (dirty) {
return gettext('You have unsaved changes. Do you really want to leave this page?');
}
});
......
define(
["jquery", "backbone", "js/views/active_video_upload_list", "js/views/previous_video_upload_list"],
function ($, Backbone, ActiveVideoUploadListView, PreviousVideoUploadListView) {
"use strict";
['jquery', 'backbone', 'js/views/active_video_upload_list', 'js/views/previous_video_upload_list'],
function($, Backbone, ActiveVideoUploadListView, PreviousVideoUploadListView) {
'use strict';
var VideosIndexFactory = function(
$contentWrapper,
postUrl,
......
define(["js/views/xblock_validation", "js/models/xblock_validation"],
function (XBlockValidationView, XBlockValidationModel) {
define(['js/views/xblock_validation', 'js/models/xblock_validation'],
function(XBlockValidationView, XBlockValidationModel) {
'use strict';
return function (validationMessages, hasEditingUrl, isRoot, validationEle) {
return function(validationMessages, hasEditingUrl, isRoot, validationEle) {
if (hasEditingUrl && !isRoot) {
validationMessages.showSummaryOnly = true;
}
var model = new XBlockValidationModel(validationMessages, {parse: true});
if (!model.get("empty")) {
if (!model.get('empty')) {
new XBlockValidationView({el: validationEle, model: model, root: isRoot}).render();
}
};
......
define(["domReady", "jquery", "underscore", "js/utils/cancel_on_escape", "js/views/utils/create_course_utils",
"js/views/utils/create_library_utils", "common/js/components/utils/view_utils"],
function (domReady, $, _, CancelOnEscape, CreateCourseUtilsFactory, CreateLibraryUtilsFactory, ViewUtils) {
"use strict";
define(['domReady', 'jquery', 'underscore', 'js/utils/cancel_on_escape', 'js/views/utils/create_course_utils',
'js/views/utils/create_library_utils', 'common/js/components/utils/view_utils'],
function(domReady, $, _, CancelOnEscape, CreateCourseUtilsFactory, CreateLibraryUtilsFactory, ViewUtils) {
'use strict';
var CreateCourseUtils = new CreateCourseUtilsFactory({
name: '.new-course-name',
org: '.new-course-org',
......@@ -39,7 +39,7 @@ define(["domReady", "jquery", "underscore", "js/utils/cancel_on_escape", "js/vie
error: 'error'
});
var saveNewCourse = function (e) {
var saveNewCourse = function(e) {
e.preventDefault();
if (CreateCourseUtils.hasInvalidRequiredFields()) {
......@@ -60,27 +60,27 @@ define(["domReady", "jquery", "underscore", "js/utils/cancel_on_escape", "js/vie
};
analytics.track('Created a Course', course_info);
CreateCourseUtils.create(course_info, function (errorMessage) {
CreateCourseUtils.create(course_info, function(errorMessage) {
$('.create-course .wrap-error').addClass('is-shown');
$('#course_creation_error').html('<p>' + errorMessage + '</p>');
$('.new-course-save').addClass('is-disabled').attr('aria-disabled', true);
});
};
var makeCancelHandler = function (addType) {
var makeCancelHandler = function(addType) {
return function(e) {
e.preventDefault();
$('.new-'+addType+'-button').removeClass('is-disabled').attr('aria-disabled', false);
$('.wrapper-create-'+addType).removeClass('is-shown');
$('.new-' + addType + '-button').removeClass('is-disabled').attr('aria-disabled', false);
$('.wrapper-create-' + addType).removeClass('is-shown');
// Clear out existing fields and errors
$('#create-'+addType+'-form input[type=text]').val('');
$('#'+addType+'_creation_error').html('');
$('.create-'+addType+' .wrap-error').removeClass('is-shown');
$('.new-'+addType+'-save').off('click');
$('#create-' + addType + '-form input[type=text]').val('');
$('#' + addType + '_creation_error').html('');
$('.create-' + addType + ' .wrap-error').removeClass('is-shown');
$('.new-' + addType + '-save').off('click');
};
};
var addNewCourse = function (e) {
var addNewCourse = function(e) {
e.preventDefault();
$('.new-course-button').addClass('is-disabled').attr('aria-disabled', true);
$('.new-course-save').addClass('is-disabled').attr('aria-disabled', true);
......@@ -95,7 +95,7 @@ define(["domReady", "jquery", "underscore", "js/utils/cancel_on_escape", "js/vie
CreateCourseUtils.configureHandlers();
};
var saveNewLibrary = function (e) {
var saveNewLibrary = function(e) {
e.preventDefault();
if (CreateLibraryUtils.hasInvalidRequiredFields()) {
......@@ -110,18 +110,18 @@ define(["domReady", "jquery", "underscore", "js/utils/cancel_on_escape", "js/vie
var lib_info = {
org: org,
number: number,
display_name: display_name,
display_name: display_name
};
analytics.track('Created a Library', lib_info);
CreateLibraryUtils.create(lib_info, function (errorMessage) {
CreateLibraryUtils.create(lib_info, function(errorMessage) {
$('.create-library .wrap-error').addClass('is-shown');
$('#library_creation_error').html('<p>' + errorMessage + '</p>');
$('.new-library-save').addClass('is-disabled').attr('aria-disabled', true);
});
};
var addNewLibrary = function (e) {
var addNewLibrary = function(e) {
e.preventDefault();
$('.new-library-button').addClass('is-disabled').attr('aria-disabled', true);
$('.new-library-save').addClass('is-disabled').attr('aria-disabled', true);
......@@ -137,22 +137,22 @@ define(["domReady", "jquery", "underscore", "js/utils/cancel_on_escape", "js/vie
};
var showTab = function(tab) {
return function(e) {
e.preventDefault();
$('.courses-tab').toggleClass('active', tab === 'courses');
$('.libraries-tab').toggleClass('active', tab === 'libraries');
$('.programs-tab').toggleClass('active', tab === 'programs');
return function(e) {
e.preventDefault();
$('.courses-tab').toggleClass('active', tab === 'courses');
$('.libraries-tab').toggleClass('active', tab === 'libraries');
$('.programs-tab').toggleClass('active', tab === 'programs');
// Also toggle this course-related notice shown below the course tab, if it is present:
$('.wrapper-creationrights').toggleClass('is-hidden', tab !== 'courses');
};
$('.wrapper-creationrights').toggleClass('is-hidden', tab !== 'courses');
};
};
var onReady = function () {
var onReady = function() {
$('.new-course-button').bind('click', addNewCourse);
$('.new-library-button').bind('click', addNewLibrary);
$('.dismiss-button').bind('click', ViewUtils.deleteNotificationHandler(function () {
$('.dismiss-button').bind('click', ViewUtils.deleteNotificationHandler(function() {
ViewUtils.reload();
}));
......
define(
["backbone", "gettext"],
['backbone', 'gettext'],
function(Backbone, gettext) {
"use strict";
'use strict';
var statusStrings = {
// Translators: This is the status of a video upload that is queued
// waiting for other uploads to complete
STATUS_QUEUED: gettext("Queued"),
STATUS_QUEUED: gettext('Queued'),
// Translators: This is the status of an active video upload
STATUS_UPLOADING: gettext("Uploading"),
STATUS_UPLOADING: gettext('Uploading'),
// Translators: This is the status of a video upload that has
// completed successfully
STATUS_COMPLETED: gettext("Upload completed"),
STATUS_COMPLETED: gettext('Upload completed'),
// Translators: This is the status of a video upload that has failed
STATUS_FAILED: gettext("Upload failed")
STATUS_FAILED: gettext('Upload failed')
};
var ActiveVideoUpload = Backbone.Model.extend(
......
define(["backbone"], function(Backbone) {
define(['backbone'], function(Backbone) {
/**
* Simple model for an asset.
*/
var Asset = Backbone.Model.extend({
defaults: {
display_name: "",
content_type: "",
thumbnail: "",
date_added: "",
url: "",
external_url: "",
portable_url: "",
locked: false
},
get_extension: function(){
var name_segments = this.get("display_name").split(".").reverse();
var asset_type = (name_segments.length > 1) ? name_segments[0].toUpperCase() : "";
return asset_type;
}
});
return Asset;
var Asset = Backbone.Model.extend({
defaults: {
display_name: '',
content_type: '',
thumbnail: '',
date_added: '',
url: '',
external_url: '',
portable_url: '',
locked: false
},
get_extension: function() {
var name_segments = this.get('display_name').split('.').reverse();
var asset_type = (name_segments.length > 1) ? name_segments[0].toUpperCase() : '';
return asset_type;
}
});
return Asset;
});
define(["backbone", "underscore"], function(Backbone, _) {
define(['backbone', 'underscore'], function(Backbone, _) {
var AssignmentGrade = Backbone.Model.extend({
defaults : {
graderType : null, // the type label (string). May be "notgraded" which implies None.
locator : null // locator for the block
defaults: {
graderType: null, // the type label (string). May be "notgraded" which implies None.
locator: null // locator for the block
},
idAttribute: 'locator',
urlRoot : '/xblock/',
urlRoot: '/xblock/',
url: function() {
// add ?fields=graderType to the request url (only needed for fetch, but innocuous for others)
return Backbone.Model.prototype.url.apply(this) + '?' + $.param({fields: 'graderType'});
......
define(["backbone", "gettext", "backbone.associations"], function(Backbone, gettext) {
define(['backbone', 'gettext', 'backbone.associations'], function(Backbone, gettext) {
var Chapter = Backbone.AssociatedModel.extend({
defaults: function() {
return {
name: "",
asset_path: "",
name: '',
asset_path: '',
order: this.collection ? this.collection.nextOrder() : 1
};
},
......@@ -11,11 +11,11 @@ define(["backbone", "gettext", "backbone.associations"], function(Backbone, gett
return !this.get('name') && !this.get('asset_path');
},
parse: function(response) {
if("title" in response && !("name" in response)) {
if ('title' in response && !('name' in response)) {
response.name = response.title;
delete response.title;
}
if("url" in response && !("asset_path" in response)) {
if ('url' in response && !('asset_path' in response)) {
response.asset_path = response.url;
delete response.url;
}
......@@ -30,19 +30,19 @@ define(["backbone", "gettext", "backbone.associations"], function(Backbone, gett
// NOTE: validation functions should return non-internationalized error
// messages. The messages will be passed through gettext in the template.
validate: function(attrs, options) {
if(!attrs.name && !attrs.asset_path) {
if (!attrs.name && !attrs.asset_path) {
return {
message: gettext("Chapter name and asset_path are both required"),
message: gettext('Chapter name and asset_path are both required'),
attributes: {name: true, asset_path: true}
};
} else if(!attrs.name) {
} else if (!attrs.name) {
return {
message: gettext("Chapter name is required"),
message: gettext('Chapter name is required'),
attributes: {name: true}
};
} else if (!attrs.asset_path) {
return {
message: gettext("asset_path is required"),
message: gettext('asset_path is required'),
attributes: {asset_path: true}
};
}
......
define(["backbone"], function(Backbone) {
define(['backbone'], function(Backbone) {
var Checklist = Backbone.Model.extend({
});
return Checklist;
......
/**
* Simple model for adding a component of a given type (for example, "video" or "html").
*/
define(["backbone"], function (Backbone) {
define(['backbone'], function(Backbone) {
return Backbone.Model.extend({
defaults: {
type: "",
type: '',
// Each entry in the template array is an Object with the following keys:
// display_name
// category (may or may not match "type")
......@@ -13,7 +13,7 @@ define(["backbone"], function (Backbone) {
templates: [],
support_legend: {}
},
parse: function (response) {
parse: function(response) {
// Returns true only for templates that both have no boilerplate and are of
// the overall type of the menu. This allows other component types to be added
// and they will get sorted alphabetically rather than just at the top.
......@@ -28,7 +28,7 @@ define(["backbone"], function (Backbone) {
this.support_legend = response.support_legend;
// Sort the templates.
this.templates.sort(function (a, b) {
this.templates.sort(function(a, b) {
// The blank problem for the current type goes first
if (isPrimaryBlankTemplate(a)) {
return -1;
......
define(['backbone'], function(Backbone){
define(['backbone'], function(Backbone) {
var Course = Backbone.Model.extend({
defaults: {
"name": ""
'name': ''
},
validate: function(attrs, options) {
if (!attrs.name) {
return gettext("You must specify a name");
return gettext('You must specify a name');
}
}
});
......
define(["backbone"], function(Backbone) {
define(['backbone'], function(Backbone) {
// single per course holds the updates and handouts
var CourseInfo = Backbone.Model.extend({
// This model class is not suited for restful operations and is considered just a server side initialized container
url: '',
defaults: {
"updates" : null, // UpdateCollection
"handouts": null // HandoutCollection
}
'updates': null, // UpdateCollection
'handouts': null // HandoutCollection
}
});
return CourseInfo;
});
define(["backbone", "jquery", "jquery.ui"], function(Backbone, $) {
define(['backbone', 'jquery', 'jquery.ui'], function(Backbone, $) {
// course update -- biggest kludge here is the lack of a real id to map updates to originals
var CourseUpdate = Backbone.Model.extend({
defaults: {
"date" : $.datepicker.formatDate('MM d, yy', new Date()),
"content" : "",
"push_notification_enabled": false,
"push_notification_selected" : false
'date': $.datepicker.formatDate('MM d, yy', new Date()),
'content': '',
'push_notification_enabled': false,
'push_notification_selected': false
},
validate: function(attrs) {
var date_exists = (attrs.date !== null && attrs.date !== "");
var date_exists = (attrs.date !== null && attrs.date !== '');
var date_is_valid_string = ($.datepicker.formatDate('MM d, yy', new Date(attrs.date)) === attrs.date);
if (!(date_exists && date_is_valid_string)) {
return {"date_required": gettext("Action required: Enter a valid date.")};
return {'date_required': gettext('Action required: Enter a valid date.')};
}
}
});
......
define(["js/models/xblock_info"],
define(['js/models/xblock_info'],
function(XBlockInfo) {
var CustomSyncXBlockInfo = XBlockInfo.extend({
sync: function(method, model, options) {
......
......@@ -2,13 +2,13 @@
* A model that simply allows the update URL to be passed
* in as an argument.
*/
define(["backbone"], function(Backbone){
define(['backbone'], function(Backbone) {
return Backbone.Model.extend({
defaults: {
"explicit_url": ""
'explicit_url': ''
},
url: function() {
return this.get("explicit_url");
return this.get('explicit_url');
}
});
});
......@@ -12,13 +12,13 @@ define([
usage: []
};
},
url : function() {
url: function() {
var parentModel = this.collection.parents[0];
return parentModel.urlRoot + '/' + encodeURIComponent(parentModel.id) + '/' + encodeURIComponent(this.id);
},
reset: function() {
this.set(this._originalAttributes, { parse: true });
this.set(this._originalAttributes, {parse: true});
},
isEmpty: function() {
......@@ -31,14 +31,14 @@ define([
name: this.get('name'),
version: this.get('version'),
usage: this.get('usage')
};
};
},
validate: function(attrs) {
if (!str.trim(attrs.name)) {
return {
message: gettext('Group name is required'),
attributes: { name: true }
attributes: {name: true}
};
}
}
......
define(["backbone", "underscore"], function(Backbone, _) {
define(['backbone', 'underscore'], function(Backbone, _) {
var LicenseModel = Backbone.Model.extend({
defaults: {
"type": null,
"options": {},
"custom": false // either `false`, or a string
'type': null,
'options': {},
'custom': false // either `false`, or a string
},
initialize: function(attributes) {
if(attributes && attributes.asString) {
if (attributes && attributes.asString) {
this.setFromString(attributes.asString);
this.unset("asString");
this.unset('asString');
}
},
toString: function() {
var custom = this.get("custom");
var custom = this.get('custom');
if (custom) {
return custom;
}
var type = this.get("type"),
options = this.get("options");
var type = this.get('type'),
options = this.get('options');
if (_.isEmpty(options)) {
return type || "";
return type || '';
}
// options are where it gets tricky
var optionStrings = _.map(options, function (value, key) {
if(_.isBoolean(value)) {
return value ? key : null
var optionStrings = _.map(options, function(value, key) {
if (_.isBoolean(value)) {
return value ? key : null;
} else {
return key + "=" + value
return key + '=' + value;
}
});
// filter out nulls
optionStrings = _.filter(optionStrings, _.identity);
// build license string and return
return type + ": " + optionStrings.join(" ");
return type + ': ' + optionStrings.join(' ');
},
setFromString: function(string, options) {
......@@ -46,8 +46,8 @@ define(["backbone", "underscore"], function(Backbone, _) {
return this.set(this.defaults, options);
}
var colonIndex = string.indexOf(":"),
spaceIndex = string.indexOf(" ");
var colonIndex = string.indexOf(':'),
spaceIndex = string.indexOf(' ');
// a string without a colon could be a custom license, or a license
// type without options
......@@ -55,16 +55,16 @@ define(["backbone", "underscore"], function(Backbone, _) {
if (spaceIndex == -1) {
// if there's no space, it's a license type without options
return this.set({
"type": string,
"options": {},
"custom": false
'type': string,
'options': {},
'custom': false
}, options);
} else {
// if there is a space, it's a custom license
return this.set({
"type": null,
"options": {},
"custom": string
'type': null,
'options': {},
'custom': string
}, options);
}
}
......@@ -74,24 +74,24 @@ define(["backbone", "underscore"], function(Backbone, _) {
optionsObj = {},
optionsString = string.substring(colonIndex + 1);
_.each(optionsString.split(" "), function(optionString) {
if (_.isEmpty(optionString)) {
return;
}
var eqIndex = optionString.indexOf("=");
if(eqIndex == -1) {
_.each(optionsString.split(' '), function(optionString) {
if (_.isEmpty(optionString)) {
return;
}
var eqIndex = optionString.indexOf('=');
if (eqIndex == -1) {
// this is a boolean flag
optionsObj[optionString] = true;
} else {
optionsObj[optionString] = true;
} else {
// this is a key-value pair
var optionKey = optionString.substring(0, eqIndex);
var optionVal = optionString.substring(eqIndex + 1);
optionsObj[optionKey] = optionVal;
}
});
var optionKey = optionString.substring(0, eqIndex);
var optionVal = optionString.substring(eqIndex + 1);
optionsObj[optionKey] = optionVal;
}
});
return this.set({
"type": type, "options": optionsObj, "custom": false,
'type': type, 'options': optionsObj, 'custom': false
}, options);
}
});
......
define(["backbone", "underscore"], function(Backbone, _) {
define(['backbone', 'underscore'], function(Backbone, _) {
var Location = Backbone.Model.extend({
defaults: {
tag: "",
org: "",
course: "",
category: "",
name: ""
tag: '',
org: '',
course: '',
category: '',
name: ''
},
toUrl: function(overrides) {
return
(overrides && overrides['tag'] ? overrides['tag'] : this.get('tag')) + "://" +
(overrides && overrides['org'] ? overrides['org'] : this.get('org')) + "/" +
(overrides && overrides['course'] ? overrides['course'] : this.get('course')) + "/" +
(overrides && overrides['category'] ? overrides['category'] : this.get('category')) + "/" +
(overrides && overrides['name'] ? overrides['name'] : this.get('name')) + "/";
return;
(overrides && overrides['tag'] ? overrides['tag'] : this.get('tag')) + '://' +
(overrides && overrides['org'] ? overrides['org'] : this.get('org')) + '/' +
(overrides && overrides['course'] ? overrides['course'] : this.get('course')) + '/' +
(overrides && overrides['category'] ? overrides['category'] : this.get('category')) + '/' +
(overrides && overrides['name'] ? overrides['name'] : this.get('name')) + '/';
},
_tagPattern : /[^:]+/g,
_fieldPattern : new RegExp('[^/]+','g'),
_tagPattern: /[^:]+/g,
_fieldPattern: new RegExp('[^/]+', 'g'),
parse: function(payload) {
if (_.isArray(payload)) {
......@@ -47,12 +47,12 @@ define(["backbone", "underscore"], function(Backbone, _) {
return payload;
}
},
getNextField : function(payload) {
getNextField: function(payload) {
try {
return this._fieldPattern.exec(payload)[0];
}
catch (err) {
return "";
return '';
}
}
});
......
define(["backbone"], function(Backbone) {
define(['backbone'], function(Backbone) {
/**
* Model used for metadata setting editors. This model does not do its own saving,
* as that is done by module_edit.coffee.
*/
var Metadata = Backbone.Model.extend({
defaults: {
"field_name": null,
"display_name": null,
"value" : null,
"explicitly_set": null,
"default_value" : null,
"options" : null,
"type" : null
'field_name': null,
'display_name': null,
'value': null,
'explicitly_set': null,
'default_value': null,
'options': null,
'type': null
},
initialize: function() {
......@@ -23,7 +23,7 @@ define(["backbone"], function(Backbone) {
* Returns true if the stored value is different, or if the "explicitly_set"
* property has changed.
*/
isModified : function() {
isModified: function() {
if (!this.get('explicitly_set') && !this.original_explicitly_set) {
return false;
}
......@@ -43,7 +43,7 @@ define(["backbone"], function(Backbone) {
/**
* The value, as shown in the UI. This may be an inherited or default value.
*/
getDisplayValue : function () {
getDisplayValue: function() {
return this.get('value');
},
......@@ -59,7 +59,7 @@ define(["backbone"], function(Backbone) {
/**
* Sets the displayed value.
*/
setValue: function (value) {
setValue: function(value) {
this.set({
explicitly_set: true,
value: value
......@@ -70,7 +70,7 @@ define(["backbone"], function(Backbone) {
* Returns the field name, which should be used for persisting the metadata
* field to the server.
*/
getFieldName: function () {
getFieldName: function() {
return this.get('field_name');
},
......@@ -78,7 +78,7 @@ define(["backbone"], function(Backbone) {
* Returns the options. This may be a array of possible values, or an object
* with properties like "max", "min" and "step".
*/
getOptions: function () {
getOptions: function() {
return this.get('options');
},
......@@ -102,14 +102,14 @@ define(["backbone"], function(Backbone) {
}
});
Metadata.SELECT_TYPE = "Select";
Metadata.INTEGER_TYPE = "Integer";
Metadata.FLOAT_TYPE = "Float";
Metadata.GENERIC_TYPE = "Generic";
Metadata.LIST_TYPE = "List";
Metadata.DICT_TYPE = "Dict";
Metadata.VIDEO_LIST_TYPE = "VideoList";
Metadata.RELATIVE_TIME_TYPE = "RelativeTime";
Metadata.SELECT_TYPE = 'Select';
Metadata.INTEGER_TYPE = 'Integer';
Metadata.FLOAT_TYPE = 'Float';
Metadata.GENERIC_TYPE = 'Generic';
Metadata.LIST_TYPE = 'List';
Metadata.DICT_TYPE = 'Dict';
Metadata.VIDEO_LIST_TYPE = 'VideoList';
Metadata.RELATIVE_TIME_TYPE = 'RelativeTime';
return Metadata;
});
define(["backbone", "js/utils/module"], function(Backbone, ModuleUtils) {
define(['backbone', 'js/utils/module'], function(Backbone, ModuleUtils) {
var ModuleInfo = Backbone.Model.extend({
urlRoot: ModuleUtils.urlRoot,
urlRoot: ModuleUtils.urlRoot,
defaults: {
"id": null,
"data": null,
"metadata" : null,
"children" : null
}
defaults: {
'id': null,
'data': null,
'metadata': null,
'children': null
}
});
return ModuleInfo;
});
define(["backbone", "gettext", "common/js/components/views/feedback_notification", "js/utils/module"],
define(['backbone', 'gettext', 'common/js/components/views/feedback_notification', 'js/utils/module'],
function(Backbone, gettext, NotificationView, ModuleUtils) {
var Section = Backbone.Model.extend({
defaults: {
"name": ""
},
validate: function(attrs, options) {
if (!attrs.name) {
return gettext("You must specify a name");
}
},
urlRoot: ModuleUtils.urlRoot,
toJSON: function() {
return {
metadata: {
display_name: this.get("name")
var Section = Backbone.Model.extend({
defaults: {
'name': ''
},
validate: function(attrs, options) {
if (!attrs.name) {
return gettext('You must specify a name');
}
},
urlRoot: ModuleUtils.urlRoot,
toJSON: function() {
return {
metadata: {
display_name: this.get('name')
}
};
},
initialize: function() {
this.listenTo(this, 'request', this.showNotification);
this.listenTo(this, 'sync', this.hideNotification);
},
showNotification: function() {
if (!this.msg) {
this.msg = new NotificationView.Mini({
title: gettext('Saving')
});
}
};
},
initialize: function() {
this.listenTo(this, "request", this.showNotification);
this.listenTo(this, "sync", this.hideNotification);
},
showNotification: function() {
if(!this.msg) {
this.msg = new NotificationView.Mini({
title: gettext("Saving")
});
this.msg.show();
},
hideNotification: function() {
if (!this.msg) { return; }
this.msg.hide();
}
this.msg.show();
},
hideNotification: function() {
if(!this.msg) { return; }
this.msg.hide();
}
});
return Section;
});
return Section;
});
define(["backbone"], function(Backbone) {
define(['backbone'], function(Backbone) {
var Advanced = Backbone.Model.extend({
var Advanced = Backbone.Model.extend({
defaults: {
defaults: {
// There will be one property per course setting. Each property's value is an object with keys
// 'display_name', 'help', 'value', and 'deprecated. The property keys are the setting names.
// For instance: advanced_modules: {display_name: "Advanced Modules, help:"Beta modules...",
// value: ["word_cloud", "split_module"], deprecated: False}
// Only 'value' is editable.
},
},
validate: function (attrs) {
validate: function(attrs) {
// Keys can no longer be edited. We are currently not validating values.
}
});
}
});
return Advanced;
return Advanced;
}); // end define()
define(["backbone", "underscore", "gettext", "js/models/validation_helpers", "js/utils/date_utils"],
define(['backbone', 'underscore', 'gettext', 'js/models/validation_helpers', 'js/utils/date_utils'],
function(Backbone, _, gettext, ValidationHelpers, DateUtils) {
var CourseDetails = Backbone.Model.extend({
defaults: {
org: '',
course_id: '',
run: '',
language: '',
start_date: null, // maps to 'start'
end_date: null, // maps to 'end'
enrollment_start: null,
enrollment_end: null,
syllabus: null,
title: '',
subtitle: '',
duration: '',
description: '',
short_description: '',
overview: '',
intro_video: null,
effort: null, // an int or null,
license: null,
course_image_name: '', // the filename
course_image_asset_path: '', // the full URL (/c4x/org/course/num/asset/filename)
banner_image_name: '',
banner_image_asset_path: '',
video_thumbnail_image_name: '',
video_thumbnail_image_asset_path: '',
pre_requisite_courses: [],
entrance_exam_enabled: '',
entrance_exam_minimum_score_pct: '50',
learning_info: [],
instructor_info: {}
},
var CourseDetails = Backbone.Model.extend({
defaults: {
org : '',
course_id: '',
run: '',
language: '',
start_date: null, // maps to 'start'
end_date: null, // maps to 'end'
enrollment_start: null,
enrollment_end: null,
syllabus: null,
title: "",
subtitle: "",
duration: "",
description: "",
short_description: "",
overview: "",
intro_video: null,
effort: null, // an int or null,
license: null,
course_image_name: '', // the filename
course_image_asset_path: '', // the full URL (/c4x/org/course/num/asset/filename)
banner_image_name: '',
banner_image_asset_path: '',
video_thumbnail_image_name: '',
video_thumbnail_image_asset_path: '',
pre_requisite_courses: [],
entrance_exam_enabled : '',
entrance_exam_minimum_score_pct: '50',
learning_info: [],
instructor_info: {}
},
validate: function(newattrs) {
validate: function(newattrs) {
// Returns either nothing (no return call) so that validate works or an object of {field: errorstring} pairs
// A bit funny in that the video key validation is asynchronous; so, it won't stop the validation.
var errors = {};
newattrs = DateUtils.convertDateStringsToObjects(
newattrs, ["start_date", "end_date", "enrollment_start", "enrollment_end"]
var errors = {};
newattrs = DateUtils.convertDateStringsToObjects(
newattrs, ['start_date', 'end_date', 'enrollment_start', 'enrollment_end']
);
if (newattrs.start_date === null) {
errors.start_date = gettext("The course must have an assigned start date.");
}
if (newattrs.start_date === null) {
errors.start_date = gettext('The course must have an assigned start date.');
}
if (newattrs.start_date && newattrs.end_date && newattrs.start_date >= newattrs.end_date) {
errors.end_date = gettext("The course end date must be later than the course start date.");
}
if (newattrs.start_date && newattrs.enrollment_start && newattrs.start_date < newattrs.enrollment_start) {
errors.enrollment_start = gettext("The course start date must be later than the enrollment start date.");
}
if (newattrs.enrollment_start && newattrs.enrollment_end && newattrs.enrollment_start >= newattrs.enrollment_end) {
errors.enrollment_end = gettext("The enrollment start date cannot be after the enrollment end date.");
}
if (newattrs.end_date && newattrs.enrollment_end && newattrs.end_date < newattrs.enrollment_end) {
errors.enrollment_end = gettext("The enrollment end date cannot be after the course end date.");
}
if (newattrs.intro_video && newattrs.intro_video !== this.get('intro_video')) {
if (this._videokey_illegal_chars.exec(newattrs.intro_video)) {
errors.intro_video = gettext("Key should only contain letters, numbers, _, or -");
}
if (newattrs.start_date && newattrs.end_date && newattrs.start_date >= newattrs.end_date) {
errors.end_date = gettext('The course end date must be later than the course start date.');
}
if (newattrs.start_date && newattrs.enrollment_start && newattrs.start_date < newattrs.enrollment_start) {
errors.enrollment_start = gettext('The course start date must be later than the enrollment start date.');
}
if (newattrs.enrollment_start && newattrs.enrollment_end && newattrs.enrollment_start >= newattrs.enrollment_end) {
errors.enrollment_end = gettext('The enrollment start date cannot be after the enrollment end date.');
}
if (newattrs.end_date && newattrs.enrollment_end && newattrs.end_date < newattrs.enrollment_end) {
errors.enrollment_end = gettext('The enrollment end date cannot be after the course end date.');
}
if (newattrs.intro_video && newattrs.intro_video !== this.get('intro_video')) {
if (this._videokey_illegal_chars.exec(newattrs.intro_video)) {
errors.intro_video = gettext('Key should only contain letters, numbers, _, or -');
}
// TODO check if key points to a real video using google's youtube api
}
if(_.has(newattrs, 'entrance_exam_minimum_score_pct')){
var range = {
min: 1,
max: 100
};
if(!ValidationHelpers.validateIntegerRange(newattrs.entrance_exam_minimum_score_pct, range)){
errors.entrance_exam_minimum_score_pct = interpolate(gettext("Please enter an integer between %(min)s and %(max)s."), range, true);
}
}
if (!_.isEmpty(errors)) return errors;
}
if (_.has(newattrs, 'entrance_exam_minimum_score_pct')) {
var range = {
min: 1,
max: 100
};
if (!ValidationHelpers.validateIntegerRange(newattrs.entrance_exam_minimum_score_pct, range)) {
errors.entrance_exam_minimum_score_pct = interpolate(gettext('Please enter an integer between %(min)s and %(max)s.'), range, true);
}
}
if (!_.isEmpty(errors)) return errors;
// NOTE don't return empty errors as that will be interpreted as an error state
},
},
_videokey_illegal_chars : /[^a-zA-Z0-9_-]/g,
_videokey_illegal_chars: /[^a-zA-Z0-9_-]/g,
set_videosource: function(newsource) {
set_videosource: function(newsource) {
// newsource either is <video youtube="speed:key, *"/> or just the "speed:key, *" string
// returns the videosource for the preview which iss the key whose speed is closest to 1
if (_.isEmpty(newsource) && !_.isEmpty(this.get('intro_video'))) this.set({'intro_video': null}, {validate: true});
if (_.isEmpty(newsource) && !_.isEmpty(this.get('intro_video'))) this.set({'intro_video': null}, {validate: true});
// TODO remove all whitespace w/in string
else {
if (this.get('intro_video') !== newsource) this.set('intro_video', newsource, {validate: true});
}
else {
if (this.get('intro_video') !== newsource) this.set('intro_video', newsource, {validate: true});
}
return this.videosourceSample();
},
return this.videosourceSample();
},
videosourceSample : function() {
if (this.has('intro_video')) return "//www.youtube.com/embed/" + this.get('intro_video');
else return "";
},
videosourceSample: function() {
if (this.has('intro_video')) return '//www.youtube.com/embed/' + this.get('intro_video');
else return '';
},
// Whether or not the course pacing can be toggled. If the course
// has already started, returns false; otherwise, returns true.
canTogglePace: function () {
return new Date() <= new Date(this.get('start_date'));
}
});
return CourseDetails;
canTogglePace: function() {
return new Date() <= new Date(this.get('start_date'));
}
});
}); // end define()
return CourseDetails;
}); // end define()
define(["backbone", "underscore", "gettext"], function(Backbone, _, gettext) {
var CourseGrader = Backbone.Model.extend({
defaults: {
"type" : "", // must be unique w/in collection (ie. w/in course)
"min_count" : 1,
"drop_count" : 0,
"short_label" : "", // what to use in place of type if space is an issue
"weight" : 0 // int 0..100
},
parse : function(attrs) {
define(['backbone', 'underscore', 'gettext'], function(Backbone, _, gettext) {
var CourseGrader = Backbone.Model.extend({
defaults: {
'type': '', // must be unique w/in collection (ie. w/in course)
'min_count': 1,
'drop_count': 0,
'short_label': '', // what to use in place of type if space is an issue
'weight': 0 // int 0..100
},
parse: function(attrs) {
// round off values while converting them to integer
if (attrs['weight']) {
attrs.weight = Math.round(attrs.weight);
}
if (attrs['min_count']) {
attrs.min_count = Math.round(attrs.min_count);
}
if (attrs['drop_count']) {
attrs.drop_count = Math.round(attrs.drop_count);
}
return attrs;
},
validate : function(attrs) {
var errors = {};
if (_.has(attrs, 'type')) {
if (_.isEmpty(attrs['type'])) {
errors.type = "The assignment type must have a name.";
if (attrs['weight']) {
attrs.weight = Math.round(attrs.weight);
}
else {
if (attrs['min_count']) {
attrs.min_count = Math.round(attrs.min_count);
}
if (attrs['drop_count']) {
attrs.drop_count = Math.round(attrs.drop_count);
}
return attrs;
},
validate: function(attrs) {
var errors = {};
if (_.has(attrs, 'type')) {
if (_.isEmpty(attrs['type'])) {
errors.type = 'The assignment type must have a name.';
}
else {
// FIXME somehow this.collection is unbound sometimes. I can't track down when
var existing = this.collection && this.collection.some(function(other) { return (other.cid != this.cid) && (other.get('type') == attrs['type']);}, this);
if (existing) {
errors.type = gettext("There's already another assignment type with this name.");
var existing = this.collection && this.collection.some(function(other) { return (other.cid != this.cid) && (other.get('type') == attrs['type']); }, this);
if (existing) {
errors.type = gettext("There's already another assignment type with this name.");
}
}
}
}
if (_.has(attrs, 'weight')) {
var intWeight = Math.round(attrs.weight); // see if this ensures value saved is int
if (!isFinite(intWeight) || /\D+/.test(attrs.weight) || intWeight < 0 || intWeight > 100) {
errors.weight = gettext("Please enter an integer between 0 and 100.");
}
else {
attrs.weight = intWeight;
if (this.collection && attrs.weight > 0) {
if (_.has(attrs, 'weight')) {
var intWeight = Math.round(attrs.weight); // see if this ensures value saved is int
if (!isFinite(intWeight) || /\D+/.test(attrs.weight) || intWeight < 0 || intWeight > 100) {
errors.weight = gettext('Please enter an integer between 0 and 100.');
}
else {
attrs.weight = intWeight;
if (this.collection && attrs.weight > 0) {
// FIXME b/c saves don't update the models if validation fails, we should
// either revert the field value to the one in the model and make them make room
// or figure out a holistic way to balance the vals across the whole
// if ((this.collection.sumWeights() + attrs.weight - this.get('weight')) > 100)
// errors.weight = "The weights cannot add to more than 100.";
}
} }
if (_.has(attrs, 'min_count')) {
var intMinCount = Math.round(attrs.min_count);
if (!isFinite(intMinCount) || /\D+/.test(attrs.min_count) || intMinCount < 1) {
errors.min_count = gettext('Please enter an integer greater than 0.');
}
}}
if (_.has(attrs, 'min_count')) {
var intMinCount = Math.round(attrs.min_count);
if (!isFinite(intMinCount) || /\D+/.test(attrs.min_count) || intMinCount < 1) {
errors.min_count = gettext("Please enter an integer greater than 0.");
else attrs.min_count = intMinCount;
}
else attrs.min_count = intMinCount;
}
if (_.has(attrs, 'drop_count')) {
var dropCount = attrs.drop_count;
var intDropCount = Math.round(dropCount);
if (!isFinite(intDropCount) || /\D+/.test(dropCount) || (_.isString(dropCount) && _.isEmpty(dropCount.trim())) || intDropCount < 0) {
errors.drop_count = gettext("Please enter non-negative integer.");
if (_.has(attrs, 'drop_count')) {
var dropCount = attrs.drop_count;
var intDropCount = Math.round(dropCount);
if (!isFinite(intDropCount) || /\D+/.test(dropCount) || (_.isString(dropCount) && _.isEmpty(dropCount.trim())) || intDropCount < 0) {
errors.drop_count = gettext('Please enter non-negative integer.');
}
else attrs.drop_count = intDropCount;
}
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) {
var template = _.template(
gettext("Cannot drop more <%= types %> assignments than are assigned.")
if (_.has(attrs, 'min_count') && _.has(attrs, 'drop_count') && !_.has(errors, 'min_count') && !_.has(errors, 'drop_count') && attrs.drop_count > attrs.min_count) {
var template = _.template(
gettext('Cannot drop more <%= types %> assignments than are assigned.')
);
errors.drop_count = template({types: attrs.type});
errors.drop_count = template({types: attrs.type});
}
if (!_.isEmpty(errors)) return errors;
}
if (!_.isEmpty(errors)) return errors;
}
});
});
return CourseGrader;
return CourseGrader;
}); // end define()
define(["backbone", "js/models/location", "js/collections/course_grader"],
define(['backbone', 'js/models/location', 'js/collections/course_grader'],
function(Backbone, Location, CourseGraderCollection) {
var CourseGradingPolicy = Backbone.Model.extend({
defaults : {
graders : null, // CourseGraderCollection
grade_cutoffs : null, // CourseGradeCutoff model
grace_period : null, // either null or { hours: n, minutes: m, ...}
minimum_grade_credit : null // either null or percentage
},
parse: function(attributes) {
if (attributes['graders']) {
var graderCollection;
var CourseGradingPolicy = Backbone.Model.extend({
defaults: {
graders: null, // CourseGraderCollection
grade_cutoffs: null, // CourseGradeCutoff model
grace_period: null, // either null or { hours: n, minutes: m, ...}
minimum_grade_credit: null // either null or percentage
},
parse: function(attributes) {
if (attributes['graders']) {
var graderCollection;
// interesting race condition: if {parse:true} when newing, then parse called before .attributes created
if (this.attributes && this.has('graders')) {
graderCollection = this.get('graders');
graderCollection.reset(attributes.graders, {parse:true});
}
else {
graderCollection = new CourseGraderCollection(attributes.graders, {parse:true});
}
attributes.graders = graderCollection;
}
if (this.attributes && this.has('graders')) {
graderCollection = this.get('graders');
graderCollection.reset(attributes.graders, {parse: true});
}
else {
graderCollection = new CourseGraderCollection(attributes.graders, {parse: true});
}
attributes.graders = graderCollection;
}
// If grace period is unset or equal to 00:00 on the server,
// it's received as null
if (attributes['grace_period'] === null) {
attributes.grace_period = {
hours: 0,
minutes: 0
}
}
if (attributes['grace_period'] === null) {
attributes.grace_period = {
hours: 0,
minutes: 0
};
}
// If minimum_grade_credit is unset or equal to 0 on the server,
// it's received as 0
if (attributes.minimum_grade_credit === null) {
attributes.minimum_grade_credit = 0;
}
return attributes;
},
gracePeriodToDate : function() {
var newDate = new Date();
if (this.has('grace_period') && this.get('grace_period')['hours'])
newDate.setHours(this.get('grace_period')['hours']);
else newDate.setHours(0);
if (this.has('grace_period') && this.get('grace_period')['minutes'])
newDate.setMinutes(this.get('grace_period')['minutes']);
else newDate.setMinutes(0);
if (this.has('grace_period') && this.get('grace_period')['seconds'])
newDate.setSeconds(this.get('grace_period')['seconds']);
else newDate.setSeconds(0);
if (attributes.minimum_grade_credit === null) {
attributes.minimum_grade_credit = 0;
}
return attributes;
},
gracePeriodToDate: function() {
var newDate = new Date();
if (this.has('grace_period') && this.get('grace_period')['hours'])
newDate.setHours(this.get('grace_period')['hours']);
else newDate.setHours(0);
if (this.has('grace_period') && this.get('grace_period')['minutes'])
newDate.setMinutes(this.get('grace_period')['minutes']);
else newDate.setMinutes(0);
if (this.has('grace_period') && this.get('grace_period')['seconds'])
newDate.setSeconds(this.get('grace_period')['seconds']);
else newDate.setSeconds(0);
return newDate;
},
parseGracePeriod : function(grace_period) {
return newDate;
},
parseGracePeriod: function(grace_period) {
// Enforce hours:minutes format
if(!/^\d{2,3}:\d{2}$/.test(grace_period)) {
return null;
}
var pieces = grace_period.split(/:/);
return {
hours: parseInt(pieces[0], 10),
minutes: parseInt(pieces[1], 10)
}
},
parseMinimumGradeCredit : function(minimum_grade_credit) {
// get the value of minimum grade credit value in percentage
if (isNaN(minimum_grade_credit)) {
return 0;
}
return parseInt(minimum_grade_credit);
},
validate : function(attrs) {
if(_.has(attrs, 'grace_period')) {
if(attrs['grace_period'] === null) {
if (!/^\d{2,3}:\d{2}$/.test(grace_period)) {
return null;
}
var pieces = grace_period.split(/:/);
return {
'grace_period': gettext('Grace period must be specified in HH:MM format.')
hours: parseInt(pieces[0], 10),
minutes: parseInt(pieces[1], 10)
};
},
parseMinimumGradeCredit: function(minimum_grade_credit) {
// get the value of minimum grade credit value in percentage
if (isNaN(minimum_grade_credit)) {
return 0;
}
}
}
if(this.get('is_credit_course') && _.has(attrs, 'minimum_grade_credit')) {
return parseInt(minimum_grade_credit);
},
validate: function(attrs) {
if (_.has(attrs, 'grace_period')) {
if (attrs['grace_period'] === null) {
return {
'grace_period': gettext('Grace period must be specified in HH:MM format.')
};
}
}
if (this.get('is_credit_course') && _.has(attrs, 'minimum_grade_credit')) {
// Getting minimum grade cutoff value
var minimum_grade_cutoff = _.min(_.values(attrs.grade_cutoffs));
if(isNaN(attrs.minimum_grade_credit) || attrs.minimum_grade_credit === null || attrs.minimum_grade_credit < minimum_grade_cutoff) {
return {
'minimum_grade_credit': interpolate(
var minimum_grade_cutoff = _.min(_.values(attrs.grade_cutoffs));
if (isNaN(attrs.minimum_grade_credit) || attrs.minimum_grade_credit === null || attrs.minimum_grade_credit < minimum_grade_cutoff) {
return {
'minimum_grade_credit': interpolate(
gettext('Not able to set passing grade to less than %(minimum_grade_cutoff)s%.'),
{minimum_grade_cutoff: minimum_grade_cutoff * 100},
true
)
};
};
}
}
}
}
}
});
});
return CourseGradingPolicy;
}); // end define()
return CourseGradingPolicy;
}); // end define()
define(["backbone", "underscore", "gettext", "js/models/chapter", "js/collections/chapter",
"backbone.associations", "cms/js/main"],
define(['backbone', 'underscore', 'gettext', 'js/models/chapter', 'js/collections/chapter',
'backbone.associations', 'cms/js/main'],
function(Backbone, _, gettext, ChapterModel, ChapterCollection) {
var Textbook = Backbone.AssociatedModel.extend({
defaults: function() {
return {
name: "",
chapters: new ChapterCollection([{}]),
showChapters: false,
editing: false
};
},
relations: [{
type: Backbone.Many,
key: "chapters",
relatedModel: ChapterModel,
collectionType: ChapterCollection
}],
initialize: function() {
this.setOriginalAttributes();
return this;
},
setOriginalAttributes: function() {
this._originalAttributes = this.parse(this.toJSON());
},
reset: function() {
this.set(this._originalAttributes, {parse: true});
},
isDirty: function() {
return !_.isEqual(this._originalAttributes, this.parse(this.toJSON()));
},
isEmpty: function() {
return !this.get('name') && this.get('chapters').isEmpty();
},
urlRoot: function() { return CMS.URL.TEXTBOOKS; },
parse: function(response) {
var ret = $.extend(true, {}, response);
if("tab_title" in ret && !("name" in ret)) {
ret.name = ret.tab_title;
delete ret.tab_title;
}
if("url" in ret && !("chapters" in ret)) {
ret.chapters = {"url": ret.url};
delete ret.url;
}
_.each(ret.chapters, function(chapter, i) {
chapter.order = chapter.order || i+1;
});
return ret;
},
toJSON: function() {
return {
tab_title: this.get('name'),
chapters: this.get('chapters').toJSON()
};
},
// NOTE: validation functions should return non-internationalized error
// messages. The messages will be passed through gettext in the template.
validate: function(attrs, options) {
if (!attrs.name) {
var Textbook = Backbone.AssociatedModel.extend({
defaults: function() {
return {
message: gettext("Textbook name is required"),
attributes: {name: true}
name: '',
chapters: new ChapterCollection([{}]),
showChapters: false,
editing: false
};
}
if (attrs.chapters.length === 0) {
},
relations: [{
type: Backbone.Many,
key: 'chapters',
relatedModel: ChapterModel,
collectionType: ChapterCollection
}],
initialize: function() {
this.setOriginalAttributes();
return this;
},
setOriginalAttributes: function() {
this._originalAttributes = this.parse(this.toJSON());
},
reset: function() {
this.set(this._originalAttributes, {parse: true});
},
isDirty: function() {
return !_.isEqual(this._originalAttributes, this.parse(this.toJSON()));
},
isEmpty: function() {
return !this.get('name') && this.get('chapters').isEmpty();
},
urlRoot: function() { return CMS.URL.TEXTBOOKS; },
parse: function(response) {
var ret = $.extend(true, {}, response);
if ('tab_title' in ret && !('name' in ret)) {
ret.name = ret.tab_title;
delete ret.tab_title;
}
if ('url' in ret && !('chapters' in ret)) {
ret.chapters = {'url': ret.url};
delete ret.url;
}
_.each(ret.chapters, function(chapter, i) {
chapter.order = chapter.order || i + 1;
});
return ret;
},
toJSON: function() {
return {
message: gettext("Please add at least one chapter"),
attributes: {chapters: true}
tab_title: this.get('name'),
chapters: this.get('chapters').toJSON()
};
} else {
// validate all chapters
var invalidChapters = [];
attrs.chapters.each(function(chapter) {
if(!chapter.isValid()) {
invalidChapters.push(chapter);
}
});
if(!_.isEmpty(invalidChapters)) {
},
// NOTE: validation functions should return non-internationalized error
// messages. The messages will be passed through gettext in the template.
validate: function(attrs, options) {
if (!attrs.name) {
return {
message: gettext("All chapters must have a name and asset"),
attributes: {chapters: invalidChapters}
message: gettext('Textbook name is required'),
attributes: {name: true}
};
}
if (attrs.chapters.length === 0) {
return {
message: gettext('Please add at least one chapter'),
attributes: {chapters: true}
};
} else {
// validate all chapters
var invalidChapters = [];
attrs.chapters.each(function(chapter) {
if (!chapter.isValid()) {
invalidChapters.push(chapter);
}
});
if (!_.isEmpty(invalidChapters)) {
return {
message: gettext('All chapters must have a name and asset'),
attributes: {chapters: invalidChapters}
};
}
}
}
}
});
return Textbook;
});
return Textbook;
});
define(["backbone", "underscore", "gettext"], function(Backbone, _, gettext) {
var FileUpload = Backbone.Model.extend({
defaults: {
"title": "",
"message": "",
"selectedFile": null,
"uploading": false,
"uploadedBytes": 0,
"totalBytes": 0,
"finished": false,
"mimeTypes": [],
"fileFormats": []
},
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.'))( // eslint-disable-line max-len
define(['backbone', 'underscore', 'gettext'], function(Backbone, _, gettext) {
var FileUpload = Backbone.Model.extend({
defaults: {
'title': '',
'message': '',
'selectedFile': null,
'uploading': false,
'uploadedBytes': 0,
'totalBytes': 0,
'finished': false,
'mimeTypes': [],
'fileFormats': []
},
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.'))( // eslint-disable-line max-len
this.formatValidTypes()
),
attributes: {selectedFile: true}
};
}
},
attributes: {selectedFile: true}
};
}
},
// Return a list of this uploader's valid file types
fileTypes: function() {
var mimeTypes = _.map(
fileTypes: function() {
var mimeTypes = _.map(
this.attributes.mimeTypes,
function(type) {
return type.split('/')[1].toUpperCase();
}
),
fileFormats = _.map(
fileFormats = _.map(
this.attributes.fileFormats,
function(type) {
return type.toUpperCase();
}
);
return mimeTypes.concat(fileFormats);
},
checkTypeValidity: function (file) {
var attrs = this.attributes,
getRegExp = function (formats) {
return mimeTypes.concat(fileFormats);
},
checkTypeValidity: function(file) {
var attrs = this.attributes,
getRegExp = function(formats) {
// Creates regular expression like: /(?:.+)\.(jpg|png|gif)$/i
return RegExp(('(?:.+)\\.(' + formats.join('|') + ')$'), 'i');
};
return RegExp(('(?:.+)\\.(' + formats.join('|') + ')$'), 'i');
};
return (attrs.mimeTypes.length === 0 && attrs.fileFormats.length === 0) ||
return (attrs.mimeTypes.length === 0 && attrs.fileFormats.length === 0) ||
_.contains(attrs.mimeTypes, file.type) ||
getRegExp(attrs.fileFormats).test(file.name);
},
},
// Return strings for the valid file types and extensions this
// uploader accepts, formatted as natural language
formatValidTypes: function() {
var attrs = this.attributes;
formatValidTypes: function() {
var attrs = this.attributes;
if(attrs.mimeTypes.concat(attrs.fileFormats).length === 1) {
return {
fileTypes: this.fileTypes()[0],
fileExtensions: '.' + this.fileTypes()[0].toLowerCase()
if (attrs.mimeTypes.concat(attrs.fileFormats).length === 1) {
return {
fileTypes: this.fileTypes()[0],
fileExtensions: '.' + this.fileTypes()[0].toLowerCase()
};
}
var or = gettext('or');
var formatTypes = function(types) {
return _.template('<%= initial %> <%= or %> <%= last %>')({
initial: _.initial(types).join(', '),
or: or,
last: _.last(types)
});
};
}
var or = gettext('or');
var formatTypes = function(types) {
return _.template('<%= initial %> <%= or %> <%= last %>')({
initial: _.initial(types).join(', '),
or: or,
last: _.last(types)
});
};
return {
fileTypes: formatTypes(this.fileTypes()),
fileExtensions: formatTypes(
return {
fileTypes: formatTypes(this.fileTypes()),
fileExtensions: formatTypes(
_.map(this.fileTypes(),
function(type) {
return '.' + type.toLowerCase();
})
)
};
}
});
};
}
});
return FileUpload;
return FileUpload;
}); // end define()
/**
* Provide helper methods for modal validation.
*/
define(["jquery"],
define(['jquery'],
function($) {
var validateIntegerRange = function(attributeVal, range) {
//Validating attribute should have an integer value and should be under the given range.
// Validating attribute should have an integer value and should be under the given range.
var isIntegerUnderRange = true;
var value = Math.round(attributeVal); // see if this ensures value saved is int
if (!isFinite(value) || /\D+/.test(attributeVal) || value < range.min || value > range.max) {
isIntegerUnderRange = false;
}
return isIntegerUnderRange;
}
};
return {
'validateIntegerRange': validateIntegerRange
}
};
});
define(["js/models/custom_sync_xblock_info"],
define(['js/models/custom_sync_xblock_info'],
function(CustomSyncXBlockInfo) {
var XBlockContainerInfo = CustomSyncXBlockInfo.extend({
urlRoots: {
......
......@@ -13,7 +13,7 @@ function(Backbone, _, str, ModuleUtils) {
'display_name': null,
'category': null,
'data': null,
'metadata' : null,
'metadata': null,
/**
* The Studio URL for this xblock, or null if it doesn't have one.
*/
......@@ -30,16 +30,16 @@ function(Backbone, _, str, ModuleUtils) {
/**
* Date of the last edit to this xblock or any of its descendants.
*/
'edited_on':null,
'edited_on': null,
/**
* User who last edited the xblock or any of its descendants. Will only be present if
* publishing info was explicitly requested.
*/
'edited_by':null,
'edited_by': null,
/**
* True iff a published version of the xblock exists.
*/
"published": null,
'published': null,
/**
* Date of the last publish of this xblock, or null if never published.
*/
......@@ -54,12 +54,12 @@ function(Backbone, _, str, ModuleUtils) {
* Note: this is not always provided as a performance optimization. It is only provided for
* verticals functioning as units.
*/
"has_changes": null,
'has_changes': null,
/**
* Represents the possible publish states for an xblock. See the documentation
* for XBlockVisibility to see a comprehensive enumeration of the states.
*/
"visibility_state": null,
'visibility_state': null,
/**
* True if the release date of the xblock is in the past.
*/
......@@ -75,7 +75,7 @@ function(Backbone, _, str, ModuleUtils) {
* This can be null if the release date is unscheduled. Will only be present if
* publishing info was explicitly requested.
*/
'release_date_from':null,
'release_date_from': null,
/**
* True if this xblock is currently visible to students. This is computed server-side
* so that the logic isn't duplicated on the client. Will only be present if
......@@ -149,16 +149,16 @@ function(Backbone, _, str, ModuleUtils) {
* The XBlock's group access rules. This is a dictionary keyed to user partition IDs,
* where the values are lists of group IDs.
*/
'group_access': null,
'group_access': null,
/**
* User partition dictionary. This is pre-processed by Studio, so it contains
* some additional fields that are not stored in the course descriptor
* (for example, which groups are selected for this particular XBlock).
*/
'user_partitions': null,
'user_partitions': null
},
initialize: function () {
initialize: function() {
// Extend our Model by helper methods.
_.extend(this, this.getCategoryHelpers());
},
......@@ -180,7 +180,7 @@ function(Backbone, _, str, ModuleUtils) {
},
createChild: function(response) {
return new XBlockInfo(response, { parse: true });
return new XBlockInfo(response, {parse: true});
},
hasChildren: function() {
......@@ -188,7 +188,7 @@ function(Backbone, _, str, ModuleUtils) {
return childInfo && childInfo.children.length > 0;
},
isPublishable: function(){
isPublishable: function() {
return !this.get('published') || this.get('has_changes');
},
......@@ -200,13 +200,13 @@ function(Backbone, _, str, ModuleUtils) {
return this.isActionRequired('draggable');
},
isChildAddable: function(){
isChildAddable: function() {
return this.isActionRequired('childAddable');
},
isHeaderVisible: function(){
if(this.get('is_header_visible') !== null) {
return this.get('is_header_visible');
isHeaderVisible: function() {
if (this.get('is_header_visible') !== null) {
return this.get('is_header_visible');
}
return true;
},
......@@ -217,7 +217,7 @@ function(Backbone, _, str, ModuleUtils) {
*/
isActionRequired: function(actionName) {
var actions = this.get('actions');
if(actions !== null) {
if (actions !== null) {
if (_.has(actions, actionName) && !actions[actionName]) {
return false;
}
......@@ -229,26 +229,26 @@ function(Backbone, _, str, ModuleUtils) {
* Return a list of convenience methods to check affiliation to the category.
* @return {Array}
*/
getCategoryHelpers: function () {
getCategoryHelpers: function() {
var categories = ['course', 'chapter', 'sequential', 'vertical'],
helpers = {};
_.each(categories, function (item) {
helpers['is' + str.titleize(item)] = function () {
_.each(categories, function(item) {
helpers['is' + str.titleize(item)] = function() {
return this.get('category') === item;
};
}, this);
return helpers;
},
},
/**
* Check if we can edit current XBlock or not on Course Outline page.
* @return {Boolean}
*/
isEditableOnCourseOutline: function() {
return this.isSequential() || this.isChapter() || this.isVertical();
},
isEditableOnCourseOutline: function() {
return this.isSequential() || this.isChapter() || this.isVertical();
},
/*
* Check whether any verification checkpoints are defined in the course.
......@@ -256,10 +256,10 @@ function(Backbone, _, str, ModuleUtils) {
* that uses the verification partition scheme.
*/
hasVerifiedCheckpoints: function() {
var partitions = this.get("user_partitions") || [];
var partitions = this.get('user_partitions') || [];
return Boolean(_.find(partitions, function(p) {
return p.scheme === "verification";
return p.scheme === 'verification';
}));
}
});
......
define(["js/models/custom_sync_xblock_info"],
define(['js/models/custom_sync_xblock_info'],
function(CustomSyncXBlockInfo) {
var XBlockOutlineInfo = CustomSyncXBlockInfo.extend({
......@@ -7,7 +7,7 @@ define(["js/models/custom_sync_xblock_info"],
},
createChild: function(response) {
return new XBlockOutlineInfo(response, { parse: true });
return new XBlockOutlineInfo(response, {parse: true});
}
});
return XBlockOutlineInfo;
......
define(["backbone", "gettext", "underscore"], function (Backbone, gettext, _) {
define(['backbone', 'gettext', 'underscore'], function(Backbone, gettext, _) {
/**
* Model for xblock validation messages as displayed in Studio.
*/
......@@ -10,21 +10,21 @@ define(["backbone", "gettext", "underscore"], function (Backbone, gettext, _) {
xblock_id: null
},
WARNING : "warning",
ERROR: "error",
NOT_CONFIGURED: "not-configured",
WARNING: 'warning',
ERROR: 'error',
NOT_CONFIGURED: 'not-configured',
parse: function(response) {
if (!response.empty) {
var summary = "summary" in response ? response.summary : {};
var messages = "messages" in response ? response.messages : [];
var summary = 'summary' in response ? response.summary : {};
var messages = 'messages' in response ? response.messages : [];
if (!summary.text) {
summary.text = gettext("This component has validation issues.");
summary.text = gettext('This component has validation issues.');
}
if (!summary.type) {
summary.type = this.WARNING;
// Possible types are ERROR, WARNING, and NOT_CONFIGURED. NOT_CONFIGURED is treated as a warning.
_.find(messages, function (message) {
_.find(messages, function(message) {
if (message.type === this.ERROR) {
summary.type = this.ERROR;
return true;
......
define([
'backbone',
'js/programs/utils/auth_utils'
],
function( Backbone, auth ) {
'backbone',
'js/programs/utils/auth_utils'
],
function(Backbone, auth) {
'use strict';
return Backbone.Collection.extend(auth.autoSync);
......
define([
'backbone',
'jquery',
'js/programs/utils/api_config',
'js/programs/collections/auto_auth_collection',
'jquery.cookie'
],
function( Backbone, $, apiConfig, AutoAuthCollection ) {
'backbone',
'jquery',
'js/programs/utils/api_config',
'js/programs/collections/auto_auth_collection',
'jquery.cookie'
],
function(Backbone, $, apiConfig, AutoAuthCollection) {
'use strict';
return AutoAuthCollection.extend({
......@@ -43,7 +43,7 @@ define([
// Adds a run back into the model for selection
addRun: function(id) {
var courseRun = _.findWhere( this.allRuns, { id: id });
var courseRun = _.findWhere(this.allRuns, {id: id});
this.create(courseRun);
},
......
define([
'backbone',
'jquery',
'js/programs/models/program_model'
],
function( Backbone, $, ProgramModel ) {
'backbone',
'jquery',
'js/programs/models/program_model'
],
function(Backbone, $, ProgramModel) {
'use strict';
return Backbone.Collection.extend({
......
define([
'backbone'
],
function( Backbone ) {
'backbone'
],
function(Backbone) {
'use strict';
return Backbone.Model.extend({
......
define([
'backbone',
'js/programs/utils/auth_utils'
],
function( Backbone, auth ) {
'backbone',
'js/programs/utils/auth_utils'
],
function(Backbone, auth) {
'use strict';
return Backbone.Model.extend(auth.autoSync);
......
define([
'backbone',
'jquery',
'js/programs/utils/api_config',
'js/programs/models/auto_auth_model',
'jquery.cookie',
'gettext'
],
function( Backbone, $, apiConfig, AutoAuthModel ) {
'backbone',
'jquery',
'js/programs/utils/api_config',
'js/programs/models/auto_auth_model',
'jquery.cookie',
'gettext'
],
function(Backbone, $, apiConfig, AutoAuthModel) {
'use strict';
return AutoAuthModel.extend({
......
define([
'backbone'
],
function( Backbone ) {
'backbone'
],
function(Backbone) {
'use strict';
return Backbone.Model.extend({
......
define([
'js/programs/utils/api_config',
'js/programs/models/auto_auth_model'
],
function( apiConfig, AutoAuthModel ) {
'js/programs/utils/api_config',
'js/programs/models/auto_auth_model'
],
function(apiConfig, AutoAuthModel) {
'use strict';
return AutoAuthModel.extend({
......
define([
'backbone',
'jquery',
'js/programs/utils/api_config',
'js/programs/models/auto_auth_model',
'gettext',
'jquery.cookie'
],
function( Backbone, $, apiConfig, AutoAuthModel, gettext ) {
'backbone',
'jquery',
'js/programs/utils/api_config',
'js/programs/models/auto_auth_model',
'gettext',
'jquery.cookie'
],
function(Backbone, $, apiConfig, AutoAuthModel, gettext) {
'use strict';
return AutoAuthModel.extend({
......@@ -37,7 +37,7 @@ define([
this.url = apiConfig.get('programsApiUrl') + 'programs/' + this.id + '/';
},
validateOrganizations: function( orgArray ) {
validateOrganizations: function(orgArray) {
/**
* The array passed to this method contains a single object representing
* the selected organization; the object contains the organization's key.
......@@ -46,61 +46,61 @@ define([
var i,
len = orgArray ? orgArray.length : 0;
for ( i = 0; i < len; i++ ) {
if ( orgArray[i].key === 'false' ) {
for (i = 0; i < len; i++) {
if (orgArray[i].key === 'false') {
return gettext('Please select a valid organization.');
}
}
},
getConfig: function( options ) {
getConfig: function(options) {
var patch = options && options.patch,
params = patch ? this.get('id') + '/' : '',
config = _.extend({ validate: true, parse: true }, {
config = _.extend({validate: true, parse: true}, {
type: patch ? 'PATCH' : 'POST',
url: apiConfig.get('programsApiUrl') + 'programs/' + params,
contentType: patch ? 'application/merge-patch+json' : 'application/json',
context: this,
// NB: setting context fails in tests
success: _.bind( this.saveSuccess, this ),
error: _.bind( this.saveError, this )
success: _.bind(this.saveSuccess, this),
error: _.bind(this.saveError, this)
});
if ( patch ) {
config.data = JSON.stringify( options.update ) || this.attributes;
if (patch) {
config.data = JSON.stringify(options.update) || this.attributes;
}
return config;
},
patch: function( data ) {
patch: function(data) {
this.save({
patch: true,
update: data
});
},
save: function( options ) {
save: function(options) {
var method,
patch = options && options.patch ? true : false,
config = this.getConfig( options );
config = this.getConfig(options);
/**
* Simplified version of code from the default Backbone save function
* http://backbonejs.org/docs/backbone.html#section-87
*/
method = this.isNew() ? 'create' : ( patch ? 'patch' : 'update' );
method = this.isNew() ? 'create' : (patch ? 'patch' : 'update');
this.sync( method, this, config );
this.sync(method, this, config);
},
saveError: function( jqXHR ) {
this.trigger( 'error', jqXHR );
saveError: function(jqXHR) {
this.trigger('error', jqXHR);
},
saveSuccess: function( data ) {
this.set({ id: data.id });
this.trigger( 'sync', this );
saveSuccess: function(data) {
this.set({id: data.id});
this.trigger('sync', this);
}
});
}
......
(function() {
'use strict';
require([
'js/programs/views/program_admin_app_view'
],
function( ProgramAdminAppView ) {
'js/programs/views/program_admin_app_view'
],
function(ProgramAdminAppView) {
return new ProgramAdminAppView();
}
);
......
define([
'backbone',
'js/programs/views/program_creator_view',
'js/programs/views/program_details_view',
'js/programs/models/program_model'
],
function( Backbone, ProgramCreatorView, ProgramDetailsView, ProgramModel ) {
'backbone',
'js/programs/views/program_creator_view',
'js/programs/views/program_details_view',
'js/programs/models/program_model'
],
function(Backbone, ProgramCreatorView, ProgramDetailsView, ProgramModel) {
'use strict';
return Backbone.Router.extend({
......@@ -15,7 +15,7 @@ define([
':id': 'programDetails'
},
initialize: function( options ) {
initialize: function(options) {
this.homeUrl = options.homeUrl;
},
......@@ -30,7 +30,7 @@ define([
},
programCreator: function() {
if ( this.programCreatorView ) {
if (this.programCreatorView) {
this.programCreatorView.destroy();
}
......@@ -39,20 +39,20 @@ define([
});
},
programDetails: function( id ) {
this.programModel = new ProgramModel({
programDetails: function(id) {
this.programModel = new ProgramModel({
id: id
});
this.programModel.on( 'sync', this.loadProgramDetails, this );
this.programModel.on('sync', this.loadProgramDetails, this);
this.programModel.fetch();
},
/**
* Starts the router.
*/
start: function () {
if ( !Backbone.history.started ) {
start: function() {
if (!Backbone.history.started) {
Backbone.history.start({
pushState: true,
root: this.root
......
......@@ -6,14 +6,14 @@
(function() {
'use strict';
if ( !window.gettext ) {
window.gettext = function (text) {
if (!window.gettext) {
window.gettext = function(text) {
return text;
};
}
if ( !window.interpolate ) {
window.interpolate = function (text) {
if (!window.interpolate) {
window.interpolate = function(text) {
return text;
};
}
......
define([
'js/programs/models/api_config_model'
],
function( ApiConfigModel ) {
'js/programs/models/api_config_model'
],
function(ApiConfigModel) {
'use strict';
/**
......@@ -16,6 +16,5 @@ define([
}
return instance;
}
);
define([
'jquery',
'underscore',
'js/programs/utils/api_config'
],
function( $, _, apiConfig ) {
'jquery',
'underscore',
'js/programs/utils/api_config'
],
function($, _, apiConfig) {
'use strict';
var auth = {
......@@ -20,11 +20,10 @@ define([
* implementation.
*
*/
sync: function( method, model, options ) {
sync: function(method, model, options) {
var oldError = options.error;
this._setHeaders( options );
this._setHeaders(options);
options.notifyOnError = false; // suppress Studio error pop-up that will happen if we get a 401
......@@ -38,7 +37,7 @@ define([
delete options.xhr; // remove the failed (401) xhr from the last try.
// update authorization header
this._setHeaders( options );
this._setHeaders(options);
Backbone.sync.call(this, method, model, options);
}.bind(this));
......@@ -54,11 +53,11 @@ define([
* Fix up headers on an imminent AJAX sync, ensuring that the JWT token is enclosed
* and that credentials are included when the request is being made cross-domain.
*/
_setHeaders: function( ajaxOptions ) {
ajaxOptions.headers = _.extend ( ajaxOptions.headers || {}, {
Authorization: 'JWT ' + apiConfig.get( 'idToken' )
_setHeaders: function(ajaxOptions) {
ajaxOptions.headers = _.extend(ajaxOptions.headers || {}, {
Authorization: 'JWT ' + apiConfig.get('idToken')
});
ajaxOptions.xhrFields = _.extend( ajaxOptions.xhrFields || {}, {
ajaxOptions.xhrFields = _.extend(ajaxOptions.xhrFields || {}, {
withCredentials: true
});
},
......@@ -67,8 +66,7 @@ define([
* Fetch a new id token from the configured endpoint, update the api config,
* and invoke the specified callback.
*/
_updateToken: function( success ) {
_updateToken: function(success) {
$.ajax({
url: apiConfig.get('authUrl'),
xhrFields: {
......@@ -76,10 +74,10 @@ define([
withCredentials: true
},
crossDomain: true
}).done(function ( data ) {
}).done(function(data) {
// save the newly-retrieved id token
apiConfig.set( 'idToken', data.id_token );
}).done( success );
apiConfig.set('idToken', data.id_token);
}).done(success);
}
}
};
......
define([
'backbone',
'backbone.validation',
'underscore',
'gettext'
],
function( Backbone, BackboneValidation, _, gettext ) {
'backbone',
'backbone.validation',
'underscore',
'gettext'
],
function(Backbone, BackboneValidation, _, gettext) {
'use strict';
var errorClass = 'has-error',
......@@ -14,52 +14,52 @@ define([
// These are the same messages provided by Backbone.Validation,
// marked for translation.
// See: http://thedersen.com/projects/backbone-validation/#overriding-the-default-error-messages.
_.extend( Backbone.Validation.messages, {
required: gettext( '{0} is required' ),
acceptance: gettext( '{0} must be accepted' ),
min: gettext( '{0} must be greater than or equal to {1}' ),
max: gettext( '{0} must be less than or equal to {1}' ),
range: gettext( '{0} must be between {1} and {2}' ),
length: gettext( '{0} must be {1} characters' ),
minLength: gettext( '{0} must be at least {1} characters' ),
maxLength: gettext( '{0} must be at most {1} characters' ),
rangeLength: gettext( '{0} must be between {1} and {2} characters' ),
oneOf: gettext( '{0} must be one of: {1}' ),
equalTo: gettext( '{0} must be the same as {1}' ),
digits: gettext( '{0} must only contain digits' ),
number: gettext( '{0} must be a number' ),
email: gettext( '{0} must be a valid email' ),
url: gettext( '{0} must be a valid url' ),
inlinePattern: gettext( '{0} is invalid' )
_.extend(Backbone.Validation.messages, {
required: gettext('{0} is required'),
acceptance: gettext('{0} must be accepted'),
min: gettext('{0} must be greater than or equal to {1}'),
max: gettext('{0} must be less than or equal to {1}'),
range: gettext('{0} must be between {1} and {2}'),
length: gettext('{0} must be {1} characters'),
minLength: gettext('{0} must be at least {1} characters'),
maxLength: gettext('{0} must be at most {1} characters'),
rangeLength: gettext('{0} must be between {1} and {2} characters'),
oneOf: gettext('{0} must be one of: {1}'),
equalTo: gettext('{0} must be the same as {1}'),
digits: gettext('{0} must only contain digits'),
number: gettext('{0} must be a number'),
email: gettext('{0} must be a valid email'),
url: gettext('{0} must be a valid url'),
inlinePattern: gettext('{0} is invalid')
});
_.extend( Backbone.Validation.callbacks, {
_.extend(Backbone.Validation.callbacks, {
// Gets called when a previously invalid field in the
// view becomes valid. Removes any error message.
valid: function( view, attr, selector ) {
var $input = view.$( '[' + selector + '~="' + attr + '"]' ),
$message = $input.siblings( messageEl );
valid: function(view, attr, selector) {
var $input = view.$('[' + selector + '~="' + attr + '"]'),
$message = $input.siblings(messageEl);
$input.removeClass( errorClass )
.removeAttr( 'data-error' );
$input.removeClass(errorClass)
.removeAttr('data-error');
$message.removeClass( errorClass )
.find( messageContent )
.text( '' );
$message.removeClass(errorClass)
.find(messageContent)
.text('');
},
// Gets called when a field in the view becomes invalid.
// Adds a error message.
invalid: function( view, attr, error, selector ) {
var $input = view.$( '[' + selector + '~="' + attr + '"]' ),
$message = $input.siblings( messageEl );
invalid: function(view, attr, error, selector) {
var $input = view.$('[' + selector + '~="' + attr + '"]'),
$message = $input.siblings(messageEl);
$input.addClass( errorClass )
.attr( 'data-error', error );
$input.addClass(errorClass)
.attr('data-error', error);
$message.addClass( errorClass )
.find( messageContent )
.text( $input.data('error') );
$message.addClass(errorClass)
.find(messageContent)
.text($input.data('error'));
}
});
......
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 ) {
'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({
......@@ -17,17 +17,17 @@ define([
'keydown': 'handleKeydown'
},
tpl: HtmlUtils.template( ModalTpl ),
tpl: HtmlUtils.template(ModalTpl),
initialize: function( options ) {
this.$parentEl = $( options.parentEl );
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.$el, this.tpl(this.content));
HtmlUtils.setHtml(this.$parentEl, HtmlUtils.HTML(this.$el));
this.postRender();
},
......@@ -47,10 +47,10 @@ define([
this.$parentEl.html('');
},
handleKeydown: function( event ) {
handleKeydown: function(event) {
var keyCode = event.keyCode;
if ( keyCode === constants.keyCodes.esc ) {
if (keyCode === constants.keyCodes.esc) {
this.destroy();
}
}
......
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 ) {
'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({
......@@ -27,19 +27,19 @@ define([
'click .js-add-course-run': 'addCourseRun'
},
tpl: HtmlUtils.template( ListTpl ),
tpl: HtmlUtils.template(ListTpl),
initialize: function( options ) {
initialize: function(options) {
this.model = new CourseModel();
Backbone.Validation.bind( this );
this.$parentEl = $( this.parentEl );
Backbone.Validation.bind(this);
this.$parentEl = $(this.parentEl);
// For managing subViews
this.courseRunViews = [];
this.courseRuns = options.courseRuns;
this.programModel = options.programModel;
if ( options.courseData ) {
if (options.courseData) {
this.model.set(options.courseData);
} else {
this.model.set({run_modes: []});
......@@ -53,13 +53,13 @@ define([
render: function() {
HtmlUtils.setHtml(this.$el, this.tpl(this.formatData()));
this.$parentEl.append( this.$el );
this.$parentEl.append(this.$el);
this.postRender();
},
postRender: function() {
var runs = this.model.get('run_modes');
if ( runs && runs.length > 0 ) {
if (runs && runs.length > 0) {
this.addCourseRuns();
}
},
......@@ -81,7 +81,7 @@ define([
$parentEl: $runsContainer
});
this.courseRunViews.push( runView );
this.courseRunViews.push(runView);
},
addCourseRuns: function() {
......@@ -89,7 +89,7 @@ define([
var runs = this.model.get('run_modes'),
$runsContainer = this.$el.find('.js-course-runs');
_.each( runs, function( run ) {
_.each(runs, function(run) {
var runModel = new CourseRunModel(),
runView;
......@@ -103,20 +103,20 @@ define([
$parentEl: $runsContainer
});
this.courseRunViews.push( runView );
this.courseRunViews.push(runView);
return runView;
}.bind(this) );
}.bind(this));
},
addCourseToProgram: function() {
var courseCodes = this.programModel.get('course_codes'),
courseData = this.model.toJSON();
if ( this.programModel.isValid( true ) ) {
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 });
courseCodes.push(_.omit(courseData, 'cid'));
this.programModel.patch({course_codes: courseCodes});
}
},
// Delete this view
......@@ -131,16 +131,16 @@ define([
destroyChildren: function() {
var runs = this.courseRunViews;
_.each( runs, function( run ) {
_.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'),
var data = $.extend({},
{courseRuns: this.courseRuns.models},
_.omit(this.programModel.toJSON(), 'run_modes'),
this.model.toJSON()
);
......@@ -153,14 +153,14 @@ define([
name = this.model.get('display_name'),
update = [];
update = _.reject( courseCodes, function(course) {
update = _.reject(courseCodes, function(course) {
return course.key === key && course.display_name === name;
});
this.programModel.patch({ course_codes: update });
this.programModel.patch({course_codes: update});
},
setCourse: function( event ) {
setCourse: function(event) {
var $form = this.$('.js-course-form'),
title = $form.find('.display-name').val(),
key = $form.find('.course-key').val();
......@@ -173,7 +173,7 @@ define([
organization: this.programModel.get('organizations')[0]
});
if ( this.model.isValid(true) ) {
if (this.model.isValid(true)) {
this.addCourseToProgram();
this.updateDOM();
this.addCourseRuns();
......@@ -181,7 +181,7 @@ define([
},
updateDOM: function() {
HtmlUtils.setHtml(this.$el, this.tpl( this.formatData() ) );
HtmlUtils.setHtml(this.$el, this.tpl(this.formatData()));
},
updateRuns: function() {
......@@ -190,13 +190,13 @@ define([
name = this.model.get('display_name'),
index;
if ( this.programModel.isValid( true ) ) {
index = _.findIndex( courseCodes, function(course) {
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 });
this.programModel.patch({course_codes: courseCodes});
}
}
});
......
define([
'backbone',
'jquery',
'underscore',
'text!templates/programs/course_run.underscore',
'edx-ui-toolkit/js/utils/html-utils'
],
function ( Backbone, $, _, CourseRunTpl, HtmlUtils ) {
'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({
......@@ -14,9 +14,9 @@ define([
'click .js-remove-run': 'removeRun'
},
tpl: HtmlUtils.template( CourseRunTpl ),
tpl: HtmlUtils.template(CourseRunTpl),
initialize: function( options ) {
initialize: function(options) {
/**
* Need the run model for the template, and the courseModel
* to keep parent view up to date with run changes
......@@ -37,12 +37,12 @@ define([
data.programStatus = this.programStatus;
if ( !!this.courseRuns ) {
if (!!this.courseRuns) {
data.courseRuns = this.courseRuns.toJSON();
}
HtmlUtils.setHtml(this.$el, this.tpl( data ) );
this.$parentEl.append( this.$el );
HtmlUtils.setHtml(this.$el, this.tpl(data));
this.$parentEl.append(this.$el);
},
// Delete this view
......@@ -52,7 +52,7 @@ define([
},
// Data returned from courseList API is not the correct format
formatData: function( data ) {
formatData: function(data) {
return {
course_key: data.id,
mode_slug: 'verified',
......@@ -72,7 +72,7 @@ define([
runs = _.clone(this.courseModel.get('run_modes')),
updatedRuns = [];
updatedRuns = _.reject( runs, function( obj ) {
updatedRuns = _.reject(runs, function(obj) {
return obj.start_date === startDate &&
obj.course_key === courseKey;
});
......@@ -96,7 +96,7 @@ define([
runs = _.clone(this.courseModel.get('run_modes')),
data = this.formatData(runObj);
this.model.set( data );
this.model.set(data);
runs.push(data);
this.courseModel.set({run_modes: runs});
this.courseRuns.removeRun(id);
......@@ -104,7 +104,7 @@ define([
// If a run has not been selected update the dropdown options
updateDropdown: function() {
if ( !this.model.get('course_key') ) {
if (!this.model.get('course_key')) {
this.render();
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment