Commit 63603d70 by Ben McMorran

Refactor shared course creation validation into create_course_utils

parent 78879ebc
define(["domReady", "jquery", "underscore", "js/utils/cancel_on_escape"], define(["domReady", "jquery", "underscore", "js/utils/cancel_on_escape", "js/views/utils/create_course_utils"],
function (domReady, $, _, CancelOnEscape) { function (domReady, $, _, CancelOnEscape, CreateCourseUtilsFactory) {
var CreateCourseUtils = CreateCourseUtilsFactory({
name: '.new-course-name',
org: '.new-course-org',
number: '.new-course-number',
run: '.new-course-run',
save: '.new-course-save',
errorWrapper: '.wrap-error',
errorMessage: '#course_creation_error',
tipError: 'span.tip-error',
error: '.error',
allowUnicode: '.allow-unicode-course-id'
}, {
shown: 'is-shown',
showing: 'is-showing',
hiding: 'is-hiding',
disabled: 'is-disabled',
error: 'error'
});
var dismissNotification = function (e) { var dismissNotification = function (e) {
e.preventDefault(); e.preventDefault();
...@@ -14,19 +32,7 @@ define(["domReady", "jquery", "underscore", "js/utils/cancel_on_escape"], ...@@ -14,19 +32,7 @@ define(["domReady", "jquery", "underscore", "js/utils/cancel_on_escape"],
var saveNewCourse = function (e) { var saveNewCourse = function (e) {
e.preventDefault(); e.preventDefault();
// One final check for empty values if (CreateCourseUtils.hasInvalidRequiredFields()) {
var errors = _.reduce(
['.new-course-name', '.new-course-org', '.new-course-number', '.new-course-run'],
function (acc, ele) {
var $ele = $(ele);
var error = validateRequiredField($ele.val());
setNewCourseFieldInErr($ele.parent('li'), error);
return error ? true : acc;
},
false
);
if (errors) {
return; return;
} }
...@@ -36,29 +42,19 @@ define(["domReady", "jquery", "underscore", "js/utils/cancel_on_escape"], ...@@ -36,29 +42,19 @@ define(["domReady", "jquery", "underscore", "js/utils/cancel_on_escape"],
var number = $newCourseForm.find('.new-course-number').val(); var number = $newCourseForm.find('.new-course-number').val();
var run = $newCourseForm.find('.new-course-run').val(); var run = $newCourseForm.find('.new-course-run').val();
analytics.track('Created a Course', { course_info = {
'org': org, org: org,
'number': number, number: number,
'display_name': display_name, display_name: display_name,
'run': run run: run
}); };
$.postJSON('/course/', { analytics.track('Created a Course', course_info);
'org': org, CreateCourseUtils.createCourse(course_info, function (errorMessage) {
'number': number, $('.wrap-error').addClass('is-shown');
'display_name': display_name, $('#course_creation_error').html('<p>' + errorMessage + '</p>');
'run': run $('.new-course-save').addClass('is-disabled');
}, });
function (data) {
if (data.url !== undefined) {
window.location = data.url;
} else if (data.ErrMsg !== undefined) {
$('.wrap-error').addClass('is-shown');
$('#course_creation_error').html('<p>' + data.ErrMsg + '</p>');
$('.new-course-save').addClass('is-disabled');
}
}
);
}; };
var cancelNewCourse = function (e) { var cancelNewCourse = function (e) {
...@@ -77,25 +73,6 @@ define(["domReady", "jquery", "underscore", "js/utils/cancel_on_escape"], ...@@ -77,25 +73,6 @@ define(["domReady", "jquery", "underscore", "js/utils/cancel_on_escape"],
$('.new-course-save').off('click'); $('.new-course-save').off('click');
}; };
// Check that a course (org, number, run) doesn't use any special characters
var validateCourseItemEncoding = function (item) {
var required = validateRequiredField(item);
if (required) {
return required;
}
if ($('.allow-unicode-course-id').val() === 'True'){
if (/\s/g.test(item)) {
return gettext('Please do not use any spaces in this field.');
}
}
else{
if (item !== encodeURIComponent(item)) {
return gettext('Please do not use any spaces or special characters in this field.');
}
}
return '';
};
var addNewCourse = function (e) { var addNewCourse = function (e) {
e.preventDefault(); e.preventDefault();
$('.new-course-button').addClass('is-disabled'); $('.new-course-button').addClass('is-disabled');
...@@ -108,68 +85,7 @@ define(["domReady", "jquery", "underscore", "js/utils/cancel_on_escape"], ...@@ -108,68 +85,7 @@ define(["domReady", "jquery", "underscore", "js/utils/cancel_on_escape"],
$cancelButton.bind('click', cancelNewCourse); $cancelButton.bind('click', cancelNewCourse);
CancelOnEscape($cancelButton); CancelOnEscape($cancelButton);
// Ensure that org/course_num/run < 65 chars. CreateCourseUtils.configureHandlers();
var validateTotalCourseItemsLength = function () {
var totalLength = _.reduce(
['.new-course-org', '.new-course-number', '.new-course-run'],
function (sum, ele) {
return sum + $(ele).val().length;
}, 0
);
if (totalLength > 65) {
$('.wrap-error').addClass('is-shown');
$('#course_creation_error').html('<p>' + gettext('The combined length of the organization, course number, and course run fields cannot be more than 65 characters.') + '</p>');
$('.new-course-save').addClass('is-disabled');
}
else {
$('.wrap-error').removeClass('is-shown');
}
};
// Handle validation asynchronously
_.each(
['.new-course-org', '.new-course-number', '.new-course-run'],
function (ele) {
var $ele = $(ele);
$ele.on('keyup', function (event) {
// Don't bother showing "required field" error when
// the user tabs into a new field; this is distracting
// and unnecessary
if (event.keyCode === 9) {
return;
}
var error = validateCourseItemEncoding($ele.val());
setNewCourseFieldInErr($ele.parent('li'), error);
validateTotalCourseItemsLength();
});
}
);
var $name = $('.new-course-name');
$name.on('keyup', function () {
var error = validateRequiredField($name.val());
setNewCourseFieldInErr($name.parent('li'), error);
validateTotalCourseItemsLength();
});
};
var validateRequiredField = function (msg) {
return msg.length === 0 ? gettext('Required field.') : '';
};
var setNewCourseFieldInErr = function (el, msg) {
if(msg) {
el.addClass('error');
el.children('span.tip-error').addClass('is-showing').removeClass('is-hiding').text(msg);
$('.new-course-save').addClass('is-disabled');
}
else {
el.removeClass('error');
el.children('span.tip-error').addClass('is-hiding').removeClass('is-showing');
// One "error" div is always present, but hidden or shown
if($('.error').length === 1) {
$('.new-course-save').removeClass('is-disabled');
}
}
}; };
var onReady = function () { var onReady = function () {
......
define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/view_helpers", "js/views/course_rerun"], define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/view_helpers", "js/views/course_rerun",
function ($, create_sinon, view_helpers, CourseRerunUtils) { "js/views/utils/create_course_utils"],
function ($, create_sinon, view_helpers, CourseRerunUtils, CreateCourseUtilsFactory) {
describe("Create course rerun page", function () { describe("Create course rerun page", function () {
var selectors = { var selectors = {
courseOrg: '.rerun-course-org', org: '.rerun-course-org',
courseNumber: '.rerun-course-number', number: '.rerun-course-number',
courseRun: '.rerun-course-run', run: '.rerun-course-run',
courseName: '.rerun-course-name', name: '.rerun-course-name',
errorField: '.tip-error', tipError: 'span.tip-error',
saveButton: '.rerun-course-save', save: '.rerun-course-save',
cancelButton: '.rerun-course-cancel', cancel: '.rerun-course-cancel',
errorMessage: '.wrapper-error' errorWrapper: '.wrapper-error',
errorMessage: '#course_rerun_error',
error: '.error',
allowUnicode: '.allow-unicode-course-id'
}, },
classes = { classes = {
shown: 'is-shown',
showing: 'is-showing',
hiding: 'is-hidden',
hidden: 'is-hidden', hidden: 'is-hidden',
error: 'error', error: 'error',
disabled: 'is-disabled', disabled: 'is-disabled',
...@@ -19,11 +26,13 @@ define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/view_helpers" ...@@ -19,11 +26,13 @@ define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/view_helpers"
}, },
mockCreateCourseRerunHTML = readFixtures('mock/mock-create-course-rerun.underscore'); mockCreateCourseRerunHTML = readFixtures('mock/mock-create-course-rerun.underscore');
var CreateCourseUtils = CreateCourseUtilsFactory(selectors, classes);
var fillInFields = function (org, number, run, name) { var fillInFields = function (org, number, run, name) {
$(selectors.courseOrg).val(org); $(selectors.org).val(org);
$(selectors.courseNumber).val(number); $(selectors.number).val(number);
$(selectors.courseRun).val(run); $(selectors.run).val(run);
$(selectors.courseName).val(name); $(selectors.name).val(name);
}; };
beforeEach(function () { beforeEach(function () {
...@@ -40,12 +49,12 @@ define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/view_helpers" ...@@ -40,12 +49,12 @@ define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/view_helpers"
describe("Field validation", function () { describe("Field validation", function () {
it("returns a message for an empty string", function () { it("returns a message for an empty string", function () {
var message = CourseRerunUtils.validateRequiredField(''); var message = CreateCourseUtils.validateRequiredField('');
expect(message).not.toBe(''); expect(message).not.toBe('');
}); });
it("does not return a message for a non empty string", function () { it("does not return a message for a non empty string", function () {
var message = CourseRerunUtils.validateRequiredField('edX'); var message = CreateCourseUtils.validateRequiredField('edX');
expect(message).toBe(''); expect(message).toBe('');
}); });
}); });
...@@ -53,43 +62,43 @@ define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/view_helpers" ...@@ -53,43 +62,43 @@ define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/view_helpers"
describe("Error messages", function () { describe("Error messages", function () {
var setErrorMessage = function(selector, message) { var setErrorMessage = function(selector, message) {
var element = $(selector).parent(); var element = $(selector).parent();
CourseRerunUtils.setNewCourseFieldInErr(element, message); CreateCourseUtils.setNewCourseFieldInErr(element, message);
return element; return element;
}; };
it("shows an error message", function () { it("shows an error message", function () {
var element = setErrorMessage(selectors.courseOrg, 'error message'); var element = setErrorMessage(selectors.org, 'error message');
expect(element).toHaveClass(classes.error); expect(element).toHaveClass(classes.error);
expect(element.children(selectors.errorField)).not.toHaveClass(classes.hidden); expect(element.children(selectors.tipError)).not.toHaveClass(classes.hidden);
expect(element.children(selectors.errorField)).toContainText('error message'); expect(element.children(selectors.tipError)).toContainText('error message');
}); });
it("hides an error message", function () { it("hides an error message", function () {
var element = setErrorMessage(selectors.courseOrg, ''); var element = setErrorMessage(selectors.org, '');
expect(element).not.toHaveClass(classes.error); expect(element).not.toHaveClass(classes.error);
expect(element.children(selectors.errorField)).toHaveClass(classes.hidden); expect(element.children(selectors.tipError)).toHaveClass(classes.hidden);
}); });
it("disables the save button", function () { it("disables the save button", function () {
setErrorMessage(selectors.courseOrg, 'error message'); setErrorMessage(selectors.org, 'error message');
expect($(selectors.saveButton)).toHaveClass(classes.disabled); expect($(selectors.save)).toHaveClass(classes.disabled);
}); });
it("enables the save button when all errors are removed", function () { it("enables the save button when all errors are removed", function () {
setErrorMessage(selectors.courseOrg, 'error message 1'); setErrorMessage(selectors.org, 'error message 1');
setErrorMessage(selectors.courseNumber, 'error message 2'); setErrorMessage(selectors.number, 'error message 2');
expect($(selectors.saveButton)).toHaveClass(classes.disabled); expect($(selectors.save)).toHaveClass(classes.disabled);
setErrorMessage(selectors.courseOrg, ''); setErrorMessage(selectors.org, '');
setErrorMessage(selectors.courseNumber, ''); setErrorMessage(selectors.number, '');
expect($(selectors.saveButton)).not.toHaveClass(classes.disabled); expect($(selectors.save)).not.toHaveClass(classes.disabled);
}); });
it("does not enable the save button when errors remain", function () { it("does not enable the save button when errors remain", function () {
setErrorMessage(selectors.courseOrg, 'error message 1'); setErrorMessage(selectors.org, 'error message 1');
setErrorMessage(selectors.courseNumber, 'error message 2'); setErrorMessage(selectors.number, 'error message 2');
expect($(selectors.saveButton)).toHaveClass(classes.disabled); expect($(selectors.save)).toHaveClass(classes.disabled);
setErrorMessage(selectors.courseOrg, ''); setErrorMessage(selectors.org, '');
expect($(selectors.saveButton)).toHaveClass(classes.disabled); expect($(selectors.save)).toHaveClass(classes.disabled);
}); });
}); });
...@@ -97,7 +106,7 @@ define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/view_helpers" ...@@ -97,7 +106,7 @@ define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/view_helpers"
var requests = create_sinon.requests(this); var requests = create_sinon.requests(this);
window.source_course_key = 'test_course_key'; window.source_course_key = 'test_course_key';
fillInFields('DemoX', 'DM101', '2014', 'Demo course'); fillInFields('DemoX', 'DM101', '2014', 'Demo course');
$(selectors.saveButton).click(); $(selectors.save).click();
create_sinon.expectJsonRequest(requests, 'POST', '/course/', { create_sinon.expectJsonRequest(requests, 'POST', '/course/', {
source_course_key: 'test_course_key', source_course_key: 'test_course_key',
org: 'DemoX', org: 'DemoX',
...@@ -105,28 +114,28 @@ define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/view_helpers" ...@@ -105,28 +114,28 @@ define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/view_helpers"
run: '2014', run: '2014',
display_name: 'Demo course' display_name: 'Demo course'
}); });
expect($(selectors.saveButton)).toHaveClass(classes.disabled); expect($(selectors.save)).toHaveClass(classes.disabled);
expect($(selectors.saveButton)).toHaveClass(classes.processing); expect($(selectors.save)).toHaveClass(classes.processing);
expect($(selectors.cancelButton)).toHaveClass(classes.hidden); expect($(selectors.cancel)).toHaveClass(classes.hidden);
}); });
it("displays an error when saving fails", function () { it("displays an error when saving fails", function () {
var requests = create_sinon.requests(this); var requests = create_sinon.requests(this);
fillInFields('DemoX', 'DM101', '2014', 'Demo course'); fillInFields('DemoX', 'DM101', '2014', 'Demo course');
$(selectors.saveButton).click(); $(selectors.save).click();
create_sinon.respondWithJson(requests, { create_sinon.respondWithJson(requests, {
ErrMsg: 'error message' ErrMsg: 'error message'
}); });
expect($(selectors.errorMessage)).not.toHaveClass(classes.hidden); expect($(selectors.errorWrapper)).not.toHaveClass(classes.hidden);
expect($(selectors.errorMessage)).toContainText('error message'); expect($(selectors.errorWrapper)).toContainText('error message');
expect($(selectors.saveButton)).not.toHaveClass(classes.processing); expect($(selectors.save)).not.toHaveClass(classes.processing);
expect($(selectors.cancelButton)).not.toHaveClass(classes.hidden); expect($(selectors.cancel)).not.toHaveClass(classes.hidden);
}); });
it("does not save if there are validation errors", function () { it("does not save if there are validation errors", function () {
var requests = create_sinon.requests(this); var requests = create_sinon.requests(this);
fillInFields('DemoX', 'DM101', '', 'Demo course'); fillInFields('DemoX', 'DM101', '', 'Demo course');
$(selectors.saveButton).click(); $(selectors.save).click();
expect(requests.length).toBe(0); expect(requests.length).toBe(0);
}); });
}); });
......
define(["domReady", "jquery", "underscore"], define(["domReady", "jquery", "underscore", "js/views/utils/create_course_utils"],
function (domReady, $, _) { function (domReady, $, _, CreateCourseUtilsFactory) {
var CreateCourseUtils = CreateCourseUtilsFactory({
name: '.rerun-course-name',
org: '.rerun-course-org',
number: '.rerun-course-number',
run: '.rerun-course-run',
save: '.rerun-course-save',
errorWrapper: '.wrapper-error',
errorMessage: '#course_rerun_error',
tipError: 'span.tip-error',
error: '.error',
allowUnicode: '.allow-unicode-course-id'
}, {
shown: 'is-shown',
showing: 'is-showing',
hiding: 'is-hidden',
disabled: 'is-disabled',
error: 'error'
});
var saveRerunCourse = function (e) { var saveRerunCourse = function (e) {
e.preventDefault(); e.preventDefault();
// One final check for errors
var errors = _.reduce(
['.rerun-course-name', '.rerun-course-org', '.rerun-course-number', '.rerun-course-run'],
function (acc, ele) {
var $ele = $(ele);
var error = validateRequiredField($ele.val());
setNewCourseFieldInErr($ele.parent('li'), error);
return error ? true : acc;
},
false
);
if (errors) { if (CreateCourseUtils.hasInvalidRequiredFields()) {
return; return;
} }
...@@ -25,31 +32,22 @@ define(["domReady", "jquery", "underscore"], ...@@ -25,31 +32,22 @@ define(["domReady", "jquery", "underscore"],
var number = $newCourseForm.find('.rerun-course-number').val(); var number = $newCourseForm.find('.rerun-course-number').val();
var run = $newCourseForm.find('.rerun-course-run').val(); var run = $newCourseForm.find('.rerun-course-run').val();
analytics.track('Reran a Course', { course_info = {
'source_course_key': source_course_key, source_course_key: source_course_key,
'org': org, org: org,
'number': number, number: number,
'display_name': display_name, display_name: display_name,
'run': run run: run
};
analytics.track('Reran a Course', course_info);
CreateCourseUtils.createCourse(course_info, function (errorMessage) {
$('.wrapper-error').addClass('is-shown').removeClass('is-hidden');
$('#course_rerun_error').html('<p>' + errorMessage + '</p>');
$('.rerun-course-save').addClass('is-disabled').removeClass('is-processing').html(gettext('Create Re-run'));
$('.action-cancel').removeClass('is-hidden');
}); });
$.postJSON('/course/', {
'source_course_key': source_course_key,
'org': org,
'number': number,
'display_name': display_name,
'run': run
},
function (data) {
if (data.url !== undefined) {
window.location = data.url;
} else if (data.ErrMsg !== undefined) {
$('.wrapper-error').addClass('is-shown').removeClass('is-hidden');
$('#course_rerun_error').html('<p>' + data.ErrMsg + '</p>');
$('.rerun-course-save').addClass('is-disabled').removeClass('is-processing').html(gettext('Create Re-run'));
$('.action-cancel').removeClass('is-hidden');
}
}
);
// Go into creating re-run state // Go into creating re-run state
$('.rerun-course-save').addClass('is-disabled').addClass('is-processing').html( $('.rerun-course-save').addClass('is-disabled').addClass('is-processing').html(
'<i class="icon icon-refresh icon-spin"></i>' + gettext('Processing Re-run Request') '<i class="icon icon-refresh icon-spin"></i>' + gettext('Processing Re-run Request')
...@@ -67,26 +65,6 @@ define(["domReady", "jquery", "underscore"], ...@@ -67,26 +65,6 @@ define(["domReady", "jquery", "underscore"],
window.location.href = '/course/'; window.location.href = '/course/';
}; };
var validateRequiredField = function (msg) {
return msg.length === 0 ? gettext('Required field.') : '';
};
var setNewCourseFieldInErr = function (el, msg) {
if(msg) {
el.addClass('error');
el.children('span.tip-error').addClass('is-shown').removeClass('is-hidden').text(msg);
$('.rerun-course-save').addClass('is-disabled');
}
else {
el.removeClass('error');
el.children('span.tip-error').addClass('is-hidden').removeClass('is-shown');
// One "error" div is always present, but hidden or shown
if($('.error').length === 1) {
$('.rerun-course-save').removeClass('is-disabled');
}
}
};
var onReady = function () { var onReady = function () {
var $cancelButton = $('.rerun-course-cancel'); var $cancelButton = $('.rerun-course-cancel');
var $courseRun = $('.rerun-course-run'); var $courseRun = $('.rerun-course-run');
...@@ -95,85 +73,7 @@ define(["domReady", "jquery", "underscore"], ...@@ -95,85 +73,7 @@ define(["domReady", "jquery", "underscore"],
$cancelButton.bind('click', cancelRerunCourse); $cancelButton.bind('click', cancelRerunCourse);
$('.cancel-button').bind('click', cancelRerunCourse); $('.cancel-button').bind('click', cancelRerunCourse);
// Check that a course (org, number, run) doesn't use any special characters CreateCourseUtils.configureHandlers();
var validateCourseItemEncoding = function (item) {
var required = validateRequiredField(item);
if (required) {
return required;
}
if ($('.allow-unicode-course-id').val() === 'True'){
if (/\s/g.test(item)) {
return gettext('Please do not use any spaces in this field.');
}
}
else{
if (item !== encodeURIComponent(item)) {
return gettext('Please do not use any spaces or special characters in this field.');
}
}
return '';
};
// Ensure that org/course_num/run < 65 chars.
var validateTotalCourseItemsLength = function () {
var totalLength = _.reduce(
['.rerun-course-org', '.rerun-course-number', '.rerun-course-run'],
function (sum, ele) {
return sum + $(ele).val().length;
}, 0
);
if (totalLength > 65) {
$('.wrap-error').addClass('is-shown');
$('#course_creation_error').html('<p>' + gettext('The combined length of the organization, course number, and course run fields cannot be more than 65 characters.') + '</p>');
$('.rerun-course-save').addClass('is-disabled');
}
else {
$('.wrap-error').removeClass('is-shown');
}
};
// Ensure that all fields are not empty
var validateFilledFields = function () {
return _.reduce(
['.rerun-course-org', '.rerun-course-number', '.rerun-course-run', '.rerun-course-name'],
function (acc, ele) {
var $ele = $(ele);
return $ele.val().length !== 0 ? acc : false;
},
true
);
};
// Handle validation asynchronously
_.each(
['.rerun-course-org', '.rerun-course-number', '.rerun-course-run'],
function (ele) {
var $ele = $(ele);
$ele.on('keyup', function (event) {
// Don't bother showing "required field" error when
// the user tabs into a new field; this is distracting
// and unnecessary
if (event.keyCode === 9) {
return;
}
var error = validateCourseItemEncoding($ele.val());
setNewCourseFieldInErr($ele.parent(), error);
validateTotalCourseItemsLength();
if(!validateFilledFields()) {
$('.rerun-course-save').addClass('is-disabled');
}
});
}
);
var $name = $('.rerun-course-name');
$name.on('keyup', function () {
var error = validateRequiredField($name.val());
setNewCourseFieldInErr($name.parent(), error);
validateTotalCourseItemsLength();
if(!validateFilledFields()) {
$('.rerun-course-save').addClass('is-disabled');
}
});
}; };
domReady(onReady); domReady(onReady);
...@@ -182,8 +82,6 @@ define(["domReady", "jquery", "underscore"], ...@@ -182,8 +82,6 @@ define(["domReady", "jquery", "underscore"],
return { return {
saveRerunCourse: saveRerunCourse, saveRerunCourse: saveRerunCourse,
cancelRerunCourse: cancelRerunCourse, cancelRerunCourse: cancelRerunCourse,
validateRequiredField: validateRequiredField,
setNewCourseFieldInErr: setNewCourseFieldInErr,
onReady: onReady onReady: onReady
}; };
}); });
/**
* Provides utilities for validating courses during creation, for both new courses and reruns.
*/
define(["jquery", "underscore", "gettext"],
function ($, _, gettext) {
return function (selectors, classes) {
var validateRequiredField, validateCourseItemEncoding, validateTotalCourseItemsLength, setNewCourseFieldInErr,
hasInvalidRequiredFields, createCourse, validateFilledFields, configureHandlers;
validateRequiredField = function (msg) {
return msg.length === 0 ? gettext('Required field.') : '';
};
// Check that a course (org, number, run) doesn't use any special characters
validateCourseItemEncoding = function (item) {
var required = validateRequiredField(item);
if (required) {
return required;
}
if ($(selectors.allowUnicode).val() === 'True') {
if (/\s/g.test(item)) {
return gettext('Please do not use any spaces in this field.');
}
}
else {
if (item !== encodeURIComponent(item)) {
return gettext('Please do not use any spaces or special characters in this field.');
}
}
return '';
};
// Ensure that org/course_num/run < 65 chars.
validateTotalCourseItemsLength = function () {
var totalLength = _.reduce(
[selectors.org, selectors.number, selectors.run],
function (sum, ele) {
return sum + $(ele).val().length;
}, 0
);
if (totalLength > 65) {
$(selectors.errorWrapper).addClass(classes.shown);
$(selectors.errorMessage).html('<p>' + gettext('The combined length of the organization, course number, and course run fields cannot be more than 65 characters.') + '</p>');
$(selectors.save).addClass(classes.disabled);
}
else {
$(selectors.errorWrapper).removeClass(classes.shown);
}
};
setNewCourseFieldInErr = function (el, msg) {
if (msg) {
el.addClass(classes.error);
el.children(selectors.tipError).addClass(classes.showing).removeClass(classes.hiding).text(msg);
$(selectors.save).addClass(classes.disabled);
}
else {
el.removeClass(classes.error);
el.children(selectors.tipError).addClass(classes.hiding).removeClass(classes.showing);
// One "error" div is always present, but hidden or shown
if ($(selectors.error).length === 1) {
$(selectors.save).removeClass(classes.disabled);
}
}
};
// One final check for empty values
hasInvalidRequiredFields = function () {
return _.reduce(
[selectors.name, selectors.org, selectors.number, selectors.run],
function (acc, ele) {
var $ele = $(ele);
var error = validateRequiredField($ele.val());
setNewCourseFieldInErr($ele.parent(), error);
return error ? true : acc;
},
false
);
};
createCourse = function (courseInfo, errorHandler) {
$.postJSON(
'/course/',
courseInfo,
function (data) {
if (data.url !== undefined) {
window.location = data.url;
} else if (data.ErrMsg !== undefined) {
errorHandler(data.ErrMsg);
}
}
);
};
// Ensure that all fields are not empty
validateFilledFields = function () {
return _.reduce(
[selectors.org, selectors.number, selectors.run, selectors.name],
function (acc, ele) {
var $ele = $(ele);
return $ele.val().length !== 0 ? acc : false;
},
true
);
};
// Handle validation asynchronously
configureHandlers = function () {
_.each(
[selectors.org, selectors.number, selectors.run],
function (ele) {
var $ele = $(ele);
$ele.on('keyup', function (event) {
// Don't bother showing "required field" error when
// the user tabs into a new field; this is distracting
// and unnecessary
if (event.keyCode === 9) {
return;
}
var error = validateCourseItemEncoding($ele.val());
setNewCourseFieldInErr($ele.parent(), error);
validateTotalCourseItemsLength();
if (!validateFilledFields()) {
$(selectors.save).addClass(classes.disabled);
}
});
}
);
var $name = $(selectors.name);
$name.on('keyup', function () {
var error = validateRequiredField($name.val());
setNewCourseFieldInErr($name.parent(), error);
validateTotalCourseItemsLength();
if (!validateFilledFields()) {
$(selectors.save).addClass(classes.disabled);
}
});
};
return {
validateRequiredField: validateRequiredField,
validateCourseItemEncoding: validateCourseItemEncoding,
validateTotalCourseItemsLength: validateTotalCourseItemsLength,
setNewCourseFieldInErr: setNewCourseFieldInErr,
hasInvalidRequiredFields: hasInvalidRequiredFields,
createCourse: createCourse,
validateFilledFields: validateFilledFields,
configureHandlers: configureHandlers
};
};
});
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