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"],
function (domReady, $, _, CancelOnEscape) {
define(["domReady", "jquery", "underscore", "js/utils/cancel_on_escape", "js/views/utils/create_course_utils"],
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) {
e.preventDefault();
......@@ -14,19 +32,7 @@ define(["domReady", "jquery", "underscore", "js/utils/cancel_on_escape"],
var saveNewCourse = function (e) {
e.preventDefault();
// One final check for empty values
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) {
if (CreateCourseUtils.hasInvalidRequiredFields()) {
return;
}
......@@ -36,29 +42,19 @@ define(["domReady", "jquery", "underscore", "js/utils/cancel_on_escape"],
var number = $newCourseForm.find('.new-course-number').val();
var run = $newCourseForm.find('.new-course-run').val();
analytics.track('Created a Course', {
'org': org,
'number': number,
'display_name': display_name,
'run': run
});
course_info = {
org: org,
number: number,
display_name: display_name,
run: run
};
$.postJSON('/course/', {
'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) {
$('.wrap-error').addClass('is-shown');
$('#course_creation_error').html('<p>' + data.ErrMsg + '</p>');
$('.new-course-save').addClass('is-disabled');
}
}
);
analytics.track('Created a Course', course_info);
CreateCourseUtils.createCourse(course_info, function (errorMessage) {
$('.wrap-error').addClass('is-shown');
$('#course_creation_error').html('<p>' + errorMessage + '</p>');
$('.new-course-save').addClass('is-disabled');
});
};
var cancelNewCourse = function (e) {
......@@ -77,25 +73,6 @@ define(["domReady", "jquery", "underscore", "js/utils/cancel_on_escape"],
$('.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) {
e.preventDefault();
$('.new-course-button').addClass('is-disabled');
......@@ -108,68 +85,7 @@ define(["domReady", "jquery", "underscore", "js/utils/cancel_on_escape"],
$cancelButton.bind('click', cancelNewCourse);
CancelOnEscape($cancelButton);
// Ensure that org/course_num/run < 65 chars.
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');
}
}
CreateCourseUtils.configureHandlers();
};
var onReady = function () {
......
define(["domReady", "jquery", "underscore"],
function (domReady, $, _) {
define(["domReady", "jquery", "underscore", "js/views/utils/create_course_utils"],
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) {
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;
}
......@@ -25,31 +32,22 @@ define(["domReady", "jquery", "underscore"],
var number = $newCourseForm.find('.rerun-course-number').val();
var run = $newCourseForm.find('.rerun-course-run').val();
analytics.track('Reran a Course', {
'source_course_key': source_course_key,
'org': org,
'number': number,
'display_name': display_name,
'run': run
course_info = {
source_course_key: source_course_key,
org: org,
number: number,
display_name: display_name,
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
$('.rerun-course-save').addClass('is-disabled').addClass('is-processing').html(
'<i class="icon icon-refresh icon-spin"></i>' + gettext('Processing Re-run Request')
......@@ -67,26 +65,6 @@ define(["domReady", "jquery", "underscore"],
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 $cancelButton = $('.rerun-course-cancel');
var $courseRun = $('.rerun-course-run');
......@@ -95,85 +73,7 @@ define(["domReady", "jquery", "underscore"],
$cancelButton.bind('click', cancelRerunCourse);
$('.cancel-button').bind('click', cancelRerunCourse);
// 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 '';
};
// 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');
}
});
CreateCourseUtils.configureHandlers();
};
domReady(onReady);
......@@ -182,8 +82,6 @@ define(["domReady", "jquery", "underscore"],
return {
saveRerunCourse: saveRerunCourse,
cancelRerunCourse: cancelRerunCourse,
validateRequiredField: validateRequiredField,
setNewCourseFieldInErr: setNewCourseFieldInErr,
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